Skip to content

rpc: retry -32005 rate-limit errors instead of crashing the ingester - #83

Open
SQD-Trevor-Agent wants to merge 1 commit into
masterfrom
alert-fix/FudppG-taiko-ratelimit-retry
Open

rpc: retry -32005 rate-limit errors instead of crashing the ingester#83
SQD-Trevor-Agent wants to merge 1 commit into
masterfrom
alert-fix/FudppG-taiko-ratelimit-retry

Conversation

@SQD-Trevor-Agent

Copy link
Copy Markdown

Problem

taiko-mainnet (and any network on a rate-limited endpoint) crash-loops its stage-2 rpc-ingest process. The ingester resumes from the last written chunk, fetches ~2k blocks, then dies with:

sqa.util.rpc.connection.RpcError: ({'code': -32005, 'message': 'rate-limit exceeded',
  'data': {'code': 'ErrAuthRateLimitRuleExceeded', ...
    'rule': 'method:eth_getTransactionReceipt', 'budget': 'public-rpc'}},
  {'method': 'eth_getTransactionReceipt', ...}, 'https://rpc.mainnet.taiko.xyz')

(top of stack: _fetch_receiptsRpcClient.batch_callRpcConnection._unpack_result)

Root cause

RpcConnection._is_retryable_error (sqa/util/rpc/connection.py) lists the JSON-RPC error codes it treats as transient/retryable:

return code in (63, 429, -32000, -32002, -32007, -32017, -32602, -32603)

-32005 ("rate-limit exceeded" / limit-exceeded, as returned by the public Taiko RPC and by most providers) is not in the set. A rate limit is inherently transient, but because it is unrecognised the RpcError propagates out of _handle_request instead of triggering the connection's back-off/retry, and the ingest program crashes. Kubernetes restarts it, it hits the same rate limit again → restart loop. HTTP-level 429s are already retried (isinstance(e, httpx.HTTPStatusError) branch); this only fixes the case where the provider returns the rate limit as a JSON-RPC error body with HTTP 200.

Fix

Add -32005 to the retryable code set so a rate-limit response backs off (_backoff, 10ms→20s schedule) and retries instead of crashing — the same handling already applied to -32000/-32002/-32007/429.

Test

tests/test_rpc_connection.py asserts -32005 is retryable, the existing transient codes stay retryable, and an unknown code (-32099) stays non-retryable. Fails on the pre-fix code, passes after:

tests/test_rpc_connection.py::RetryableErrorTest::test_rate_limit_code_is_retryable  # red -> green
3 passed

Falsification

If, after this change, the ingester still crash-loops on Taiko with a different error code (not -32005), or the crash is a genuine non-transient failure rather than rate limiting, this fix is insufficient. Separately, retry only makes the process survive the rate limit — if the public endpoint's sustained throughput is below what ingest needs, throughput/lag is a provider-capacity matter (a higher-limit/dedicated Taiko endpoint) and is being handed to infra on-call; that is orthogonal to the crash-loop this PR removes.

The RPC connection classified JSON-RPC error -32005 ("rate-limit
exceeded") as non-retryable, so a transient rate limit from the
upstream endpoint propagated as a fatal RpcError and crashed the
ingest process into a restart loop. Add -32005 to the retryable
codes so the connection backs off and retries, mirroring the other
transient server codes already handled.
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