Skip to content

fix(sdk): retry transient 5xx on read-only RPC calls - #1006

Closed
arkhindi12 wants to merge 1 commit into
conduit-protocol:mainfrom
arkhindi12:fix/980-custom-fetch-retry
Closed

arkhindi12 wants to merge 1 commit into
conduit-protocol:mainfrom
arkhindi12:fix/980-custom-fetch-retry

Conversation

@arkhindi12

@arkhindi12 arkhindi12 commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Closes #980.

Problem

customFetch handed every request straight to the user's fetch. A single
502/503 from a public Soroban RPC node — routine during deploys and LB
rotations — surfaced as a hard failure, even though the same read succeeds a
second later.

Why the fix keys off the JSON-RPC method, not the HTTP verb

Soroban RPC is POST-only, so "retry GET" would never fire in practice, and
"retry POST" would replay sendTransaction and submit a transaction twice.

isIdempotentRequest() therefore looks at the body: requests whose JSON-RPC
method is read-only (getLatestLedger, getAccount, getLedgerEntries,
simulateTransaction, getEvents, getTransaction, getFeeStats, …) are
retryable; everything else, sendTransaction above all, is sent exactly once.

Behaviour

  • 3 attempts by default, exponential backoff (250 ms → 2 s) with jitter so a
    fleet of workers does not retry in lockstep
  • retries dropped connections, not just 5xx
  • 501 is excluded — "not implemented" will not fix itself
  • abort-aware: an aborted signal stops the loop and rejects immediately
  • the response body is drained before a retry so the connection is reusable
  • setCustomFetchRetryPolicy() / resetCustomFetchRetryPolicy() for tuning

Tests

src/tests/custom-fetch-retry.test.ts — 8 cases: 503→200 retried, exhaustion
surfaces the last 5xx, 404 and 501 not retried, sendTransaction never
retried, dropped connection retried, maxAttempts: 1 disables retrying, and
a nonsensical policy throws instead of silently clamping.

Test Files  1 passed (1)
     Tests  8 passed (8)

Rebased on main after #1004. npx tsc --noEmit and this PR's test suite are green on the current head.

…l#980)

Soroban RPC is POST-only, so retrying by HTTP verb would either never fire
or replay sendTransaction. Decide idempotency from the JSON-RPC method
instead: getLatestLedger/getAccount/simulateTransaction and friends are
safe to replay, sendTransaction never is.

Three attempts by default with exponential backoff plus jitter, abort-aware,
and 501 is excluded because 'not implemented' will not fix itself.
@arkhindi12

Copy link
Copy Markdown
Contributor Author

Closing this — the issue was resolved by #1015, so this PR is superseded. Thanks for the review queue space.

@arkhindi12 arkhindi12 closed this Oct 19, 2026
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.

src/custom-fetch.ts: add request retry logic for idempotent GET calls on 502/503/504 gateway errors

1 participant