Skip to content

perf(cache-proxy): parallel peer fills, origin hedge, tighter probe timeout - #1047

Open
EDsCODE wants to merge 1 commit into
mainfrom
eric/cache-proxy-peer-path
Open

perf(cache-proxy): parallel peer fills, origin hedge, tighter probe timeout#1047
EDsCODE wants to merge 1 commit into
mainfrom
eric/cache-proxy-peer-path

Conversation

@EDsCODE

@EDsCODE EDsCODE commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Problem

Per-request phase timing (#1045) localized essentially all block-request serving time to FetchFromPeers: cold-scan trails showed peer_ms accounting for ~100% of dur_ms (median 714ms post-deploy, 237ms steady state per request, versus 8ms for a pure local hit), with 16% of cold requests burning the full 1s has-probe timeout and 2-block requests costing exactly two sequential peer rounds.

Changes

Three independent changes, each aimed at one measured cost:

  • peerHasTimeout 1s → 150ms. FetchFromPeers waits for every peer's "no" before giving up, so the slowest peer in the fleet gates every cold fill. Healthy peers answer probes in single-digit ms while the origin path costs ~200ms — once a probe has gone unanswered for ~150ms, waiting longer only delays a faster fallback.
  • Concurrent peer fills. Fills for a request's missing blocks are launched together (bounded at 8) instead of one FetchFromPeers round per block in sequence. Phase 1 consumes each block's result in order, so miss-run coalescing, single-flight keys, and the lastIdx clamp logic are unchanged. The fill check precedes the Has check so a block landed by our own prefetch is attributed to peer, not local.
  • Wait budget with origin hedge. A 400ms absolute deadline (shared across the request's fills, since they start together) bounds how long a request waits on the peer path. Blocks not filled by then join the coalesced origin run; the fill keeps running in the background and still populates the cache. Previously a holder that stalled its body transfer could pin the request for the 30s get timeout.

New observability: cache_proxy_peer_fill_hedged_total counter and a blocks_hedged field on the Served. log line.

Testing

  • TestServeBlockAlignedPeerFillsRunConcurrently: peer /cache/get handlers gate on all three of a request's blocks being fetched at once against a closed origin — a regression to sequential fills can never open the gate and fails loudly instead of assembling the response.
  • TestServeBlockAlignedHedgesSlowPeerToOrigin: a peer that claims the block but stalls the transfer; asserts the request completes from origin within the budget and the hedge counter increments.
  • Full package suite passes with -race (the pre-existing TestHandleConnectLogsOpenAndClose race reproduces on unmodified main and is untouched).

…imeout

Phase-timing trails from production cold scans showed 100% of block-request
serving time inside FetchFromPeers (median 714ms cold / 237ms steady-state
per request, vs 8ms for local hits), with 16% of cold requests burning the
full 1s has-probe timeout, and 2-block requests costing exactly twice the
single-block peer round.

Three changes, each aimed at one measured cost:

- peerHasTimeout 1s -> 150ms: healthy peers answer probes in single-digit
  ms while the origin path costs ~200ms, so waiting longer for the fleet's
  slowest "no" only delays a faster fallback.
- Peer fills for a request's missing blocks now run concurrently (bounded
  at 8) instead of one FetchFromPeers round per block in sequence; phase 1
  consumes results in order, so miss-run coalescing and single-flight keys
  are unchanged.
- A wait budget (400ms, shared absolute deadline across the request's
  fills) hedges stalled fills to the coalesced origin fetch instead of
  pinning the request on the 30s body-transfer timeout; the fill keeps
  running in the background and still populates the cache. New counter
  cache_proxy_peer_fill_hedged_total and Served. field blocks_hedged track
  how often that happens.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Test Impact Plan

Deterministic summary of how this PR changes tests, CI runners, and coverage-risk signals.

Summary

Area Added Changed Deleted
Test files 0 1 0
E2E/journey files 0 0 0
Workflow files 0 0 0

Signals

  • Test cases: +2 / -0
  • Assertions: +9 / -0
  • Skips or known failures added: 0
  • Workflow continue-on-error added: 0
  • Workflow path filters added: 0
  • Test commands removed from justfile: 0
  • E2E/journey retry lines added: 0

Coverage risk: neutral or increased

No coverage-reduction warnings detected.

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