Skip to content

rpc-keyed harness: record sub-millisecond latency without truncation#1128

Merged
Flotapponnier merged 1 commit into
devfrom
fix/rpc-keyed-latency-sub-ms
Jul 12, 2026
Merged

rpc-keyed harness: record sub-millisecond latency without truncation#1128
Flotapponnier merged 1 commit into
devfrom
fix/rpc-keyed-latency-sub-ms

Conversation

@Flotapponnier

Copy link
Copy Markdown
Collaborator

time.Duration.Milliseconds() returns int64 and truncates every probe under 1 ms to zero. QuickNode is measured via the Mobula shared paid fleet whose endpoints are peer-adjacent to the harness (short RTT + HTTP keep-alive), so a significant share of successful probes returned in ~0.3 to 0.9 ms and were recorded as 0 ms in Prometheus. The 24h aggregate on the BNB + US-East cell landed at effectively 0 ms and rendered as QuickNode leads at 0 ms on the UI.

Fix

// before
latencyMs = float64(time.Since(start).Milliseconds())

// after
latencyMs = float64(time.Since(start).Nanoseconds()) / 1e6

Same wall-clock delta, real precision preserved down to microsecond granularity. Every other provider (Alchemy, Chainstack, Ankr, Helius, Infura) was already above 1 ms because their endpoints are not peer-adjacent to the harness, so the truncation never bit them and this fix does not change their numbers within noise.

Deploy sequence

  • Merge to dev, then to main.
  • Rebuild + redeploy the rpc-keyed-latency Railway service so the harness picks up the new binary.
  • Prometheus starts recording microsecond-accurate latency immediately after redeploy.
  • 24h aggregate cell on ?chain=bnb&region=us-east will heal over the following window.
  • No changes to Prom queries, materialized store shape, /api/stat, or UI code needed. Bench data path is identical, only the source metric precision changes.

Verified

  • go build ./... in harnesses/rpc-keyed-latency: clean
  • Grep confirms the only .Milliseconds() call in the harness was the one on time.Since; the metrics client is unaffected

Test plan

  • Merge to dev
  • Redeploy the rpc-keyed-latency Railway service
  • Wait 30 minutes and re-query ocb:rpc_latency_milliseconds:p50_24h{provider="quicknode", chain="bnb", region="us-east"} on Prom, verify the value climbs off 0
  • Full 24h heal for the aggregate leaderboard cell
  • Then promote to main + vercel --prod

time.Duration.Milliseconds() returns int64 and truncates every probe
under 1 ms to zero. QuickNode is measured via the Mobula shared paid
fleet whose endpoints are peer-adjacent to the harness (short RTT +
HTTP keep-alive), so a significant share of successful probes returned
in ~0.3 to 0.9 ms and were recorded as 0 ms in Prometheus. The 24h
aggregate on the BNB + US-East cell landed at effectively 0 ms and
rendered as 'QuickNode leads at 0 ms' on
/benchmarks/rpc-keyed-latency?chain=bnb&region=us-east.

Fix: latencyMs = float64(time.Since(start).Nanoseconds()) / 1e6. Same
wall-clock delta, real precision preserved down to microsecond
granularity. Every other provider stays within noise (their probes
were already above 1 ms so the truncation never bit them).

Requires a Railway harness rebuild + redeploy to take effect on
staging and production (bench 069 runs on Railway, not the shared
worker VPS). The materialized store will catch up on the next 24h
window after redeploy.
@Flotapponnier
Flotapponnier merged commit 2902d6a into dev Jul 12, 2026
1 check failed
@Flotapponnier
Flotapponnier deleted the fix/rpc-keyed-latency-sub-ms branch July 12, 2026 15:28
Flotapponnier added a commit that referenced this pull request Jul 12, 2026
…1128)

time.Duration.Milliseconds() returns int64 and truncates every probe
under 1 ms to zero. QuickNode is measured via the Mobula shared paid
fleet whose endpoints are peer-adjacent to the harness (short RTT +
HTTP keep-alive), so a significant share of successful probes returned
in ~0.3 to 0.9 ms and were recorded as 0 ms in Prometheus. The 24h
aggregate on the BNB + US-East cell landed at effectively 0 ms and
rendered as 'QuickNode leads at 0 ms' on
/benchmarks/rpc-keyed-latency?chain=bnb&region=us-east.

Fix: latencyMs = float64(time.Since(start).Nanoseconds()) / 1e6. Same
wall-clock delta, real precision preserved down to microsecond
granularity. Every other provider stays within noise (their probes
were already above 1 ms so the truncation never bit them).

Requires a Railway harness rebuild + redeploy to take effect on
staging and production (bench 069 runs on Railway, not the shared
worker VPS). The materialized store will catch up on the next 24h
window after redeploy.

Co-authored-by: Florent Tapponnier <contact@mobula.io>
Flotapponnier pushed a commit that referenced this pull request Jul 13, 2026
Histogram Buckets grew from [50, 100, 200, 500, 1000, 2000, 5000, 10000]
to [10, 25, 50, 100, 200, 500, 1000, 2000, 5000, 10000]. Near Intents
on solver-cached corridors (HyperCore in particular) returns via a
1Click coordinator fast path in <50ms, and the previous scheme lumped
every one of those observations into (0, 50] so histogram_quantile
linearly interpolated to ~25ms regardless of true value. The p50 shown
on /benchmarks/bridge-quote-latency?chain=HyperCore was therefore a
bucket floor, not a measurement. Sub-50 buckets let the real bimodality
surface.

Also swap Observe(float64(quoteLatency.Milliseconds())) for
Observe(float64(quoteLatency.Nanoseconds()) / 1e6) across all 6
per-bridge observers (across, debridge, lifi, mobula, nearintents,
relay). int64 Milliseconds() truncates every sub-1ms round-trip to 0,
same bug class as the RPC harness fix in PR #1128. Not a hot path here
(network RTT dominates), but keeps precision consistent with the new
low buckets and cheap to fix while we are already touching each file.

Bench YAML methodology + FAQ updated to reflect the new bucket set.
Flotapponnier added a commit that referenced this pull request Jul 13, 2026
…gram buckets (#1152)

* spec: missing store blob for a live bench throws instead of caching the miss (bnb-rpc awaiting incident)

* bridge-monitor: sub-50ms buckets + nanosecond precision on Observe

Histogram Buckets grew from [50, 100, 200, 500, 1000, 2000, 5000, 10000]
to [10, 25, 50, 100, 200, 500, 1000, 2000, 5000, 10000]. Near Intents
on solver-cached corridors (HyperCore in particular) returns via a
1Click coordinator fast path in <50ms, and the previous scheme lumped
every one of those observations into (0, 50] so histogram_quantile
linearly interpolated to ~25ms regardless of true value. The p50 shown
on /benchmarks/bridge-quote-latency?chain=HyperCore was therefore a
bucket floor, not a measurement. Sub-50 buckets let the real bimodality
surface.

Also swap Observe(float64(quoteLatency.Milliseconds())) for
Observe(float64(quoteLatency.Nanoseconds()) / 1e6) across all 6
per-bridge observers (across, debridge, lifi, mobula, nearintents,
relay). int64 Milliseconds() truncates every sub-1ms round-trip to 0,
same bug class as the RPC harness fix in PR #1128. Not a hot path here
(network RTT dominates), but keeps precision consistent with the new
low buckets and cheap to fix while we are already touching each file.

Bench YAML methodology + FAQ updated to reflect the new bucket set.

---------

Co-authored-by: Florent Tapponnier <contact@mobula.io>
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