feat(relay): frame-forwarded and grace-expiry counters (#58)#88
Conversation
Adds two Prometheus counters via nil-safe hooks on *Registry, keeping
the prometheus dep out of registry.go and forward.go:
- pyrycode_relay_frames_forwarded_total{direction} — incremented after
a successful sink Send in StartPhoneForwarder / StartBinaryForwarder.
direction is a hard-coded constant set {phone_to_binary,
binary_to_phone}, cardinality 2.
- pyrycode_relay_grace_expiries_total — incremented from
handleGraceExpiry's success branch, after the pointer-identity guard
so stale fires do not increment.
Per-direction CounterVec children are pre-bound from WithLabelValues so
the hot-path hook is a single atomic Inc.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Code Review: #58Decision: PASS Findings
SummaryClean implementation of the hooks-on- The hook-field doc comments on Tests cover all four AC paths (phone→binary success + Send error + no-binary; binary→phone success + malformed + unknown conn_id + sink Send err; grace real-eviction + stale-fire; race freedom under cancel-replace cycles). The race test is appropriately structured to assert only the race-detector's verdict and a presence-of-metric check, not an exact value (the cancel-replace race window makes that schedule-dependent). CI green (test, security, image-scan). |
Adds the per-ticket codebase note and an evergreen feature doc for the
two new Prometheus counters (frames_forwarded_total{direction},
grace_expiries_total) wired via nil-safe func() hooks on *Registry to
keep prometheus out of registry.go and forward.go. INDEX.md gains a
single entry for the new feature doc.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
What
Third slice of the metrics rollout (split from #37). Adds two Prometheus counters routed through nil-safe
func()hooks on*Registry, keeping theprometheusdep out ofregistry.goandforward.go:pyrycode_relay_frames_forwarded_total{direction}— labelled by direction (phone_to_binary|binary_to_phone), incremented exactly once per successful sinkSend. No increment onBinaryFormiss, marshal error, unknownconn_id, malformed envelope, or per-sinkSenderror.pyrycode_relay_grace_expiries_total— scalar, incremented fromRegistry.handleGraceExpiry's success branch, after the pointer-identity guard so stale fires do not increment.Per-direction
CounterVecchildren are pre-bound fromWithLabelValuesso the hot-path hook is a single atomicInc.Issue
Closes #58. Depends on #59 (registry scaffolding) — already merged.
Architecture compliance
Follows
docs/specs/architecture/58-frame-and-grace-counters.md:metrics_forward.go,metrics_grace.go) mirrormetrics_connections.go's shape.r.mu" constraints.directionlabel values are hard-coded constants, never sourced from request state;grace_expiries_totalis label-less. Documented in both spec and prod files.docs/knowledge/codebase/58.mdand INDEX update are explicitly deferred to the documentation phase per § Open questions (precedent: relay: adopt prometheus/client_golang and introduce metrics registry scaffolding #59/relay: localhost-only /metrics listener with bind-address validation #60/relay: wire pyrycode_relay_connected_{binaries,phones} gauges into registry events #61).Testing
New
internal/relay/metrics_counters_test.go(four tests, all inpackage relayso they reusefakeConn/fakePhone/fakeBinary/fakeBinarySourcewithout duplication):TestForwardMetrics_PhoneToBinary_OnlyOnSuccess— asserts +3 on three successful Sends, then verifies the counter does NOT move onSenderror and on the no-binary path.TestForwardMetrics_BinaryToPhone_OnlyOnSuccess— interleaves 3 successful frames with malformed-envelope, unknown-conn_id, and phone-Send-error paths; counter ends at exactly 3.TestGraceMetrics_OnlyOnRealEviction— +1 on a real eviction, then a cancel-and-replace scenario verifies the stale fire does NOT move the counter past 1.TestGraceMetrics_RaceFreedom— 16 goroutines × 200 ops hammeringClaimServer/ScheduleReleaseServer/ cancel-replace cycles; race detector verdict is the assertion. Counter scrape sanity-checked at the end.A shared
assertCounterhelper mirrorsassertGaugefrommetrics_connections_test.go— substring-match on the literal text-format line, same posture (the response body also carriespromhttp_metric_handler_*self-instrumentation lines).make vetcleanmake test(race) cleanmake buildcleanTest plan
make vet,make test,make buildall green/metricsfrom a running relay; confirm three new series appear with the expected names and label cardinality🤖 Generated with Claude Code