Skip to content

Add HTTP request coalescing (in-flight deduplication) - #2

Merged
wille merged 3 commits into
masterfrom
request-coalescing
Jul 10, 2026
Merged

Add HTTP request coalescing (in-flight deduplication)#2
wille merged 3 commits into
masterfrom
request-coalescing

Conversation

@wille

@wille wille commented Jul 9, 2026

Copy link
Copy Markdown
Owner

What

Adds request coalescing on the HTTP JSON-RPC path: identical concurrent read requests collapse into a single upstream call, and that one response is fanned back to every caller.

This reduces redundant load on upstream providers and lowers rate-limit (429) exposure under bursty traffic (e.g. many clients polling eth_getTransactionReceipt for the same hash).

How

  • chain.Chain gains Coalesceable(method string) bool — a per-chain allowlist of read-only, idempotent methods. The EVM allowlist is shared by eth and tron; solana and btc have their own. Default-deny: anything not on the list is sent individually.
  • core.Endpoint holds a singleflight.Group. A single coalesceable request runs through it, keyed by method + params (the JSON-RPC id is excluded since it varies per client).
  • The provider failover loop is extracted into forwardWithFailover. The coalescing leader runs it under a detached context (context.WithoutCancel) so one client disconnecting can't cancel the shared upstream call the others are waiting on. Each caller writes a value-copy of the shared response stamped with its own id (never mutating the shared response).
  • Batches and non-allowlisted methods bypass coalescing entirely.
  • New haprovider_coalesced_requests_total{endpoint,method} metric; README updated.

Scope / non-goals

  • HTTP only. WebSocket coalescing and batch coalescing are out of scope for now.
  • Allowlist is deliberately conservative (default-deny): a read method not yet listed simply isn't coalesced until added.

Testing

  • Unit + integration tests in internal/coalesce_test.go, driving the real handler concurrently against a hit-counting mock upstream:
    • 20 identical concurrent eth_call1 upstream hit; every client gets the result with its own id echoed.
    • 10 identical eth_sendRawTransaction10 hits (never coalesced).
    • Distinct params → not coalesced; batches → not coalesced.
  • go test -race ./... green (stable across repeated runs); go vet and golangci-lint clean.

wille added 3 commits July 9, 2026 18:04
Collapse identical concurrent read requests on the HTTP JSON-RPC path into a
single upstream call and fan the response back to every caller, reducing
redundant provider load and rate-limit exposure under bursty traffic.

- chain.Chain gains Coalesceable(method): a per-chain allowlist of read-only,
  idempotent methods (EVM allowlist shared by eth+tron; solana and btc have
  their own). Default-deny: anything not listed is sent individually.
- Endpoint holds a singleflight.Group; a single coalesceable request runs
  through it keyed by method+params (id excluded).
- The failover loop is extracted into forwardWithFailover; the leader runs it
  under a detached context so one client disconnecting can't cancel the shared
  call. Each caller writes a copy of the shared response stamped with its own id.
- Batches and non-allowlisted methods bypass coalescing entirely.
- New haprovider_coalesced_requests_total metric; README updated.
@wille
wille merged commit 3472aad into master Jul 10, 2026
1 check passed
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