How do I handle rate limit errors (429)?
Handle Unison 429 rate limit responses with exponential backoff and jitter to avoid thundering-herd retries.
I'm getting 429 errors under load. How should I back off?
A 429 means you've exceeded your request rate for the current window. The response includes a Retry-After header (in seconds) when available — respect it. When it's absent, use exponential backoff with jitter.
Minimal retry pattern (TypeScript)
async function callWithRetry(fn: () => Promise<Response>, maxAttempts = 5): Promise<Response> {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const res = await fn();
if (res.status !== 429) return res;
const retryAfter = res.headers.get('Retry-After');
const delay = retryAfter
? parseInt(retryAfter, 10) * 1000
: Math.min(1000 * 2 ** attempt + Math.random() * 500, 30_000);
await new Promise(r => setTimeout(r, delay));
}
throw new Error('Rate limit retries exhausted');
}Python equivalent
import time, random, httpx
def call_with_retry(fn, max_attempts=5):
for attempt in range(max_attempts):
res = fn()
if res.status_code != 429:
return res
retry_after = res.headers.get("Retry-After")
delay = int(retry_after) if retry_after else min(2 ** attempt + random.random(), 30)
time.sleep(delay)
raise RuntimeError("Rate limit retries exhausted")Reducing 429s upstream
- Batch ingestion: spread large backlogs over time rather than ingesting everything at once.
- Cache recall results: for a given query+actor combination, recall results are stable for seconds to minutes. Cache aggressively at the application layer.
- Queue writes: funnel ingest calls through a queue with a configurable rate rather than hitting the API directly from every request.
How do I read Unison error responses?
Understand the Unison error envelope: every error is a JSON object with a snake_case code and a human-readable message.
How do I resolve a 409 concurrency conflict?
Handle optimistic-concurrency 409 conflicts when writing to the Unison brain: re-read the current version, merge, and retry.