-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
Problem
rpcclient methods (GetBlockCount, GetBlockHash, SendRawTransaction, etc.) don't accept context.Context. Callers have no way to cancel or timeout individual RPC calls. When a node is slow or unresponsive, GetBlockCount() blocks for up to 600s (10 retries x 60s HTTP timeout) with no way to interrupt it.
The root cause is in handleSendPostMessage — HTTP requests are created via http.NewRequest (without context), and the retry loop has no ctx.Done() check:
// infrastructure.go — retry loop, no cancellation
for i := 0; tries == 0 || i < tries; i++ {
resp, err = httpClient.Do(req) // 60s timeout each
<-time.After(backoff) // no select on ctx.Done()
}I searched existing issues and PRs — #2450 and #2451 improve shutdown and dial timeout handling but don't address per-request context cancellation. No other open issues cover this.
Use case
We run a HAProxy health checker that polls BTC nodes via GetBlockCount(). HAProxy sends a TCP probe every N seconds; each probe spawns a goroutine calling GetBlockCount(). When a node hangs:
- Each probe creates a new goroutine blocked in
GetBlockCountfor ~600s - New probes arrive faster than old ones complete
- Goroutines accumulate — we observed 117 leaked goroutines on staging
We worked around this with a singleflight pattern + context timeout at our layer, but the proper fix belongs in the library.
Proposed approach
Non-breaking: add *WithContext variants alongside existing methods (same pattern as database/sql).
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
count, err := client.GetBlockCountWithContext(ctx)Minimal changes to infrastructure.go:
jsonRequest— addctx context.ContextfieldhandleSendPostMessage—http.NewRequestWithContext(jReq.ctx, ...)+ctx.Done()in retry loopClient.SendCmdCtx(ctx, cmd)— new method, passes context throughGetBlockCountWithContext(ctx)— first method using the plumbing
Builds on #2450 and #2451. Remaining methods can follow in incremental PRs. ~80-100 lines total.
Happy to submit a PR if maintainers agree with the approach.
Related
- rpcclient: make shutdown interrupt in-flight POSTs #2451 — shutdown interrupts in-flight POSTs (same area)
- rpcclient: ensure http dial respects timeout #2450 — dial respects timeout (merged)
- rpcclient.Client doesn't reuse network connections #1323 — connection reuse (related transport issue)