Summary
Have each Jaws instance publish stable dependency tags for its own status metrics. JaWS owns these tags and dirties them itself; applications only attach a published tag to an Element that renders the corresponding metric.
Start with:
- active Requests;
- registered Sessions; and
- a new per-instance atomic error count.
The maintenance loop can sample these metrics, retain the previous sample, and dirty a metric's published tag when the sampled value changes.
Public contract
Expose stable, comparable tags along the lines of:
func (jw *Jaws) ActiveRequestCountTag() any
func (jw *Jaws) SessionCountTag() any
func (jw *Jaws) ErrorCountTag() any
The exact names and concrete representation are open, but each tag must be:
- unique to both the
Jaws instance and the metric;
- stable for that instance's lifetime; and
- valid anywhere an ordinary JaWS dependency tag is accepted.
Applications do not maintain counters, install lifecycle callbacks, poll, or call Dirty. They read RequestCounts, SessionCount, or ErrorCount normally and register the tag published by that same Jaws instance.
Maintenance sampling
On each maintenance pass:
- perform normal Request and Session maintenance;
- take one per-instance snapshot of active Requests, registered Sessions, and the atomic error count;
- compare each value with its previous maintenance sample;
- retain the new sample; and
- after releasing core locks, dirty each published tag whose value changed.
These tags are coalesced state invalidations, not event streams. Several changes between maintenance passes may produce one update, and a value that changes and returns to its previous value between samples need not produce an update. A resulting getter must observe the latest sampled value.
This also gives the feature an explicit update cadence: status Elements converge within the maintenance interval plus the normal dirty-update interval.
Error counter
Add an ErrorCount() uint64-style accessor backed by a per-Jaws atomic counter. Increment it exactly once at a defined point in the JaWS error-reporting path so delegated Request.Log and MustLog calls cannot double-count. Logger latency and a panic in Logger.Error must not affect the count.
Document whether non-nil reports without a configured Logger and reports after shutdown count. The maintenance sampler only needs an atomic load and treats the value like the other metrics.
Additional metric
Pending() is the other existing first-class per-instance lifecycle gauge worth supporting. A published pending-Request tag can use the same maintenance sampling mechanism without adding lifecycle callbacks.
The total value from RequestCounts may also be useful for a status panel. It could have its own tag or share a request-status tag with active and pending counts; keeping one request-status tag makes the public API smaller, while separate tags avoid unrelated rerenders.
Serving state is not useful as an on-change UI tag because stopping Serve also stops delivery. Uptime would dirty continuously, and internal queue depths, subscriptions, and dirty backlogs do not currently have public metric contracts.
Acceptance criteria
- Real multi-Request tests show that remaining live pages update a tagged active-Request count after another Request connects and disconnects.
- Session tests cover count changes from creation,
AutoSession, close, and maintenance expiry.
- Concurrent logging tests verify exact atomic counting and error-tag updates under the race detector.
- Sampling and dirtying preserve the
Jaws.mu -> Request.mu -> Session.mu ordering and never call dirty dispatch while a core lock is held.
- Cross-instance tests prove that changing one
Jaws instance cannot dirty Elements registered with another instance's corresponding tag.
- Documentation states the sampling/coalescing behavior and distinguishes active Requests (running page/WebSocket loops, so tabs count separately) from registered Sessions (which include the normal disconnect grace period).
Summary
Have each
Jawsinstance publish stable dependency tags for its own status metrics. JaWS owns these tags and dirties them itself; applications only attach a published tag to an Element that renders the corresponding metric.Start with:
The maintenance loop can sample these metrics, retain the previous sample, and dirty a metric's published tag when the sampled value changes.
Public contract
Expose stable, comparable tags along the lines of:
The exact names and concrete representation are open, but each tag must be:
Jawsinstance and the metric;Applications do not maintain counters, install lifecycle callbacks, poll, or call
Dirty. They readRequestCounts,SessionCount, orErrorCountnormally and register the tag published by that sameJawsinstance.Maintenance sampling
On each maintenance pass:
These tags are coalesced state invalidations, not event streams. Several changes between maintenance passes may produce one update, and a value that changes and returns to its previous value between samples need not produce an update. A resulting getter must observe the latest sampled value.
This also gives the feature an explicit update cadence: status Elements converge within the maintenance interval plus the normal dirty-update interval.
Error counter
Add an
ErrorCount() uint64-style accessor backed by a per-Jawsatomic counter. Increment it exactly once at a defined point in the JaWS error-reporting path so delegatedRequest.LogandMustLogcalls cannot double-count. Logger latency and a panic inLogger.Errormust not affect the count.Document whether non-nil reports without a configured Logger and reports after shutdown count. The maintenance sampler only needs an atomic load and treats the value like the other metrics.
Additional metric
Pending()is the other existing first-class per-instance lifecycle gauge worth supporting. A published pending-Request tag can use the same maintenance sampling mechanism without adding lifecycle callbacks.The total value from
RequestCountsmay also be useful for a status panel. It could have its own tag or share a request-status tag with active and pending counts; keeping one request-status tag makes the public API smaller, while separate tags avoid unrelated rerenders.Serving state is not useful as an on-change UI tag because stopping
Servealso stops delivery. Uptime would dirty continuously, and internal queue depths, subscriptions, and dirty backlogs do not currently have public metric contracts.Acceptance criteria
AutoSession, close, and maintenance expiry.Jaws.mu -> Request.mu -> Session.muordering and never call dirty dispatch while a core lock is held.Jawsinstance cannot dirty Elements registered with another instance's corresponding tag.