Skip to content

feat(metrics): resync seq-gap histogram, drop per-resync logs - #42

Open
mikhail-dcl wants to merge 1 commit into
mainfrom
feat/resync-seq-gap-metric
Open

feat(metrics): resync seq-gap histogram, drop per-resync logs#42
mikhail-dcl wants to merge 1 commit into
mainfrom
feat/resync-seq-gap-metric

Conversation

@mikhail-dcl

Copy link
Copy Markdown
Collaborator

Problem

Resync fallback to STATE_FULL for subject … (lastKnownSeq=…, gap=…) fired once per served resync at Warning, with a matching Information line beside it — too noisy to leave on, and the only useful signal in it was a single number.

Change

That number is now a histogram: latestSeq − knownSeq recorded per served resync, bucketed dense around Peers:SnapshotHistoryCapacity (the ring-eviction cliff that decides targeted-delta vs STATE_FULL), with a dedicated 0 edge so "client was already current" is distinguishable from "one publish behind".

Split into delta / full outcomes, so the fallback rate the old LogWarning conveyed reads off the full series' own _count — no extra counter needed.

  • Console dashboard: one merged Resync Seq Gap row in the Latency group with the usual P50/P95/P99 window+lifetime columns, sparkline on window P99. Per-outcome split is Grafana-only, same convention as Peer RTT.
  • Prometheus: dcl_pulse_resync_seq_gap{outcome="delta|full"} native histogram.
  • The sibling per-request log in ResyncRequestHandler drops to Debug — it fires 1:1 with the removed pair, so leaving it at Information would have kept the console just as noisy. Still available when chasing a single client.

Follows the delta_staleness / peer_rtt pattern end to end; ResyncOutcome/ResyncOutcomes mirrors the existing ConnectionClass/ConnectionClasses idiom.

Note for review

ResyncRequest.KnownSeq is unvalidated client input — FieldValidator has no rule for it. The first cut used a serial-number cast, (int)(latestSeq - lastKnownSeq), to clamp a baseline ahead of the latest publish. That only disambiguates within 2^31: a client sending known_seq = 3_000_000_000 against a small latestSeq recorded a 1.29-billion sample, swamping _sum and the +Inf bucket and faking the exact "sustained loss / stalled client" signal the docs tell operators to watch for.

Now the ordering is tested before subtracting. Seq doesn't wrap within a session — it's server-assigned from 0 and reset to the sentinel on disconnect, the same assumption every other Seq comparison in PeerSimulation already makes with plain </>.

Testing

660 tests pass. New coverage: gap magnitude on both outcomes, outcome routing in the collector, Prometheus label/bucket shape, the already-current case, and four TestCases across the ahead-baseline range (two of which fail against the pre-fix arithmetic).

🤖 Generated with Claude Code

Replaces two per-resync log lines with a bucketed distribution of
latestSeq - knownSeq, split by outcome (targeted delta / STATE_FULL):
one merged percentile row on the console dashboard, and
dcl_pulse_resync_seq_gap{outcome} in Prometheus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant