How to handle 429 errors, timeouts and transient API failures without creating duplicate orders or retry storms.
In plain English
This guide focuses on making data and code predictable: define types, validate inputs, handle errors explicitly and test the cases that should fail.
Retry example
If an API says “try again later,” wait with backoff. If the previous request may have created an order, check current broker state before sending the same order again.
Retry reads more freely than writes
Repeating a price request is usually less dangerous than repeating an order request. For write operations, a timeout is ambiguous: the remote side may have accepted the order even though your client never received the response.
Exponential backoff with jitter
import random, time
def delay(attempt, base=0.5, cap=20):
return min(cap, base * (2 ** attempt)) + random.uniform(0, 0.25)
for attempt in range(5):
r = call_api()
if r.status_code != 429:
break
time.sleep(delay(attempt))
Idempotency before retries
If the provider supports an idempotency key, use it. If it does not, maintain your own event/order intent table and reconcile broker state before resubmitting an uncertain action.
Respect Retry-After
When an API supplies Retry-After, prefer it over your own guessed delay. Log rate-limit responses separately from network failures so you can see whether the bot design is too chatty.
Before you rely on this in production
- Input types are validated.
- Errors are handled instead of swallowed.
- Tests include invalid and boundary cases.
- Secrets are not embedded in code or test fixtures.
