Manual rate-limit backoff
Catch a 429 / 503, honor Retry-After, and retry — taking over from the SDK's built-in auto-retry when you need to.
The HTTP client already retries transport failures and 503 responses for the
idempotent verbs (encode, whoami, capabilities) with exponential backoff,
honoring a server Retry-After. For most callers that is the right behavior —
you do nothing. The non-idempotent verbs (recall, forget, link, unlink,
plan, reason) run exactly once and are never auto-retried.
When you want different behavior — enqueue the write, log it, or fall through to
a degraded path — catch the typed error yourself. Every HTTP failure throws a
BrainHttpError carrying status, code, and message (status: 0 means a
transport failure or timeout).
import { BrainHttpClient, BrainHttpError } from '@brain-db/sdk';
const brain = new BrainHttpClient({ apiKey: process.env.BRAIN_API_KEY! });
async function encodeOrEnqueue(text: string) {
try {
return await brain.encode({ text });
} catch (err) {
if (err instanceof BrainHttpError && (err.status === 429 || err.status === 503)) {
// Enqueue for a worker to retry later instead of blocking here.
await jobQueue.enqueue('brain-encode', { text, notBefore: Date.now() + 1000 });
return null;
}
throw err; // 4xx (bad request, auth) and everything else: propagate.
}
}from brain_db_sdk import BrainHttpClient, BrainHttpError
brain = BrainHttpClient(os.environ['BRAIN_API_KEY'])
def encode_or_enqueue(text: str):
try:
return brain.encode(text)
except BrainHttpError as err:
if err.status in (429, 503):
job_queue.enqueue('brain-encode', {'text': text, 'not_before': time.time() + 1})
return None
raise # 4xx and everything else: propagate.Manual retry with backoff
If you want retry behavior but with your own logging, do it yourself. Honor a
server Retry-After when present, otherwise back off exponentially:
async function recallWithRetry(query: string, attempts = 3) {
let delay = 250;
for (let i = 0; i < attempts; i++) {
try {
return await brain.recall({ query });
} catch (err) {
const retryable = err instanceof BrainHttpError && (err.status === 429 || err.status === 503);
if (!retryable || i === attempts - 1) throw err;
console.warn(`brain ${err.status}, retrying in ${delay}ms`, { attempt: i });
await new Promise((r) => setTimeout(r, delay));
delay *= 2;
}
}
throw new Error('unreachable');
}On the wire client
The wire client (BrainClient) raises a ServerError whose category is
ResourceExhausted (rate/quota) or Unavailable (shard busy), and those carry
a retryAfterMs hint. Use the isRetryable(err) helper to branch, or let the
built-in withRetry combinator drive it. See
Errors and Retries.
Don't loop indefinitely. If the server is genuinely overloaded the retry budget is cooperation — a few attempts with backoff is the polite ceiling. After that, propagate the error and let the caller degrade.
Was this page helpful?