00-andruia-consultant
Usar al iniciar o mejorar un proyecto de IA: diagnostica código y restricciones, propone skills existentes y redacta tareas y un…
Implement bounded, idempotency-aware API throttling, backoff, and retry handling for 429 and transient 5xx responses.
Claude Code
$ npx -y skills add sickn33/agentic-awesome-skills --skill api-rate-limit-handler --agent claude-code
Codex
$ npx skills add sickn33/agentic-awesome-skills --skill api-rate-limit-handler -a codex -y
Cursor
$ npx skills add sickn33/agentic-awesome-skills --skill api-rate-limit-handler -a cursor -y
Gemini CLI
$ npx skills add sickn33/agentic-awesome-skills --skill api-rate-limit-handler -a gemini-cli -y
GitHub Copilot
$ npx skills add sickn33/agentic-awesome-skills --skill api-rate-limit-handler -a github-copilot -y
OpenCode
$ npx skills add sickn33/agentic-awesome-skills --skill api-rate-limit-handler -a opencode -y
Windsurf
$ npx skills add sickn33/agentic-awesome-skills --skill api-rate-limit-handler -a windsurf -y
name: api-rate-limit-handler description: "Implement bounded, idempotency-aware API throttling, backoff, and retry handling for 429 and transient 5xx responses." category: development risk: safe source: self source_type: self date_added: "2026-08-26" author: Prajeeth-12 tags: [rate-limiting, retry, backoff, api, resilience, throttle, 429] tools: [claude, cursor, codex, gemini] license: "MIT"
A skill for implementing production-grade rate limiting, exponential backoff, and retry strategies when integrating with external APIs. Prevents cascading failures, respects upstream quotas, and keeps your application resilient under load.
Determine whether a failed request is retryable or terminal.
| Status | Classification | Action | |--------|---------------|--------| | 200-299 | Success | Return response | | 400, 401, 403, 404 | Terminal client error | Do not retry — fix the request | | 408, 429 | Retryable (rate limit / timeout) | Retry with backoff | | 500, 502, 503, 504 | Retryable (server error) | Retry with backoff |
Always check upstream hints before computing your own delay.
function getRetryDelay(
response: Response,
attempt: number,
maxDelayMs = 60_000
): number {
// Prefer upstream hints
const retryAfter = response.headers.get("Retry-After");
if (retryAfter) {
const seconds = Number(retryAfter);
if (Number.isFinite(seconds) && seconds >= 0) {
return seconds * 1000;
}
// HTTP-date format
const date = new Date(retryAfter).getTime();
if (Number.isFinite(date)) {
return Math.max(0, date - Date.now());
}
}
// GitHub documents x-ratelimit-reset as Unix epoch seconds.
const resetHeader = response.headers.get("x-ratelimit-reset");
const githubReset = resetHeader === null || resetHeader.trim() === "" ? NaN : Number(resetHeader);
if (Number.isFinite(githubReset)) {
return Math.max(0, githubReset * 1000 - Date.now());
}
// Fallback: capped exponential backoff with full jitter.
const cap = Math.min(1000 * 2 ** attempt, maxDelayMs);
return Math.floor(Math.random() * cap);
}Upstream hints are minimum waits; never truncate them to retry early. If a hint exceeds the remaining operation budget, stop without scheduling another request. The cap applies only to fallback backoff.
Provider-specific reset headers do not share one unit or format. For example, some APIs return durations while GitHub returns epoch seconds. Parse an additional header only after checking that provider's current documentation.
async function fetchWithRetry(
url: string,
options: RequestInit,
maxRetries = 3,
maxElapsedMs = 120_000,
retryNonIdempotent = false
): Promise<Response> {
const startedAt = Date.now();
const method = (options.method ?? "GET").toUpperCase();
const replaySafe = ["GET", "HEAD", "OPTIONS", "PUT", "DELETE"].includes(method)
|| retryNonIdempotent;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.ok) return response;
// Terminal errors — do not retry
if (![408, 429, 500, 502, 503, 504].includes(response.status)) {
throw new Error(`Terminal error ${response.status}: ${response.statusText}`);
}
if (!replaySafe) {
throw new Error(
`${method} was not retried because replay safety was not explicitly established`
);
}
// Retryable — but exhausted attempts
if (attempt === maxRetries) {
throw new Error(`Failed after ${maxRetries} retries: ${response.status}`);
}
const remaining = maxElapsedMs - (Date.now() - startedAt);
const delay = getRetryDelay(response, attempt);
if (remaining <= 0 || delay > remaining) {
throw new Error(`Retry cannot be scheduled within ${maxElapsedMs}ms`);
}
// Release the connection before waiting when the body is not needed.
await response.body?.cancel();
console.warn(
`Request failed (${response.status}), retrying in ${Math.round(delay)}ms (attempt ${attempt + 1}/${maxRetries})`
);
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error("Unreachable");
}Prevent hitting upstream limits in the first place with a token bucket or sliding window.
class TokenBucket {
private tokens: number;
private lastRefill: number;
private queue: Promise<void> = Promise.resolve();
constructor(
private maxTokens: number,
private refillRate: number // tokens per second
) {
this.tokens = maxTokens;
this.lastRefill = Date.now();
}
async acquire(): Promise<void> {
const ticket = this.queue.then(() => this.acquireOnce());
this.queue = ticket.catch(() => undefined);
return ticket;
}
private async acquireOnce(): Promise<void> {
this.refill();
if (this.tokens < 1) {
const waitMs = ((1 - this.tokens) / this.refillRate) * 1000;
await new Promise(resolve => setTimeout(resolve, waitMs));
this.refill();
}
this.tokens -= 1;
}
private refill(): void {
const now = Date.now();
const elapsed = (now - this.lastRefill) / 1000;
this.tokens = Math.min(this.maxTokens, this.tokens + elapsed * this.refillRate);
this.lastRefill = now;
}
}
// Usage: limit to 60 requests/minute
const limiter = new TFind reusable instructions for your project, inspect their complete files, and keep an exact skill set you can review and reuse.
Usar al iniciar o mejorar un proyecto de IA: diagnostica código y restricciones, propone skills existentes y redacta tareas y un…
Security audit, hardening, threat modeling (STRIDE/PASTA), Red/Blue Team, OWASP checks, code review, incident response, and…
Usar para crear o mejorar una skill de Andru.ia: define entradas y resultados, redacta SKILL.md con ejemplos y límites, valida la…
Usar tras definir el sector de un proyecto: prepara un dossier en español con contexto, normas aplicables, patrones UX y riesgos,…
AI-powered presentation generation via the 2slides API — create slides from text, match a reference image style, summarize…
360 feedback register: reviewer, subject, review cycle, visibility, due date and score, as CSV, SQL, JSON Schema or Notion on…
Use your assigned AgentMail inbox to read email tasks, explicitly send or reply, and check delivery. Provided automatically by…
Create a new Architecture Decision Record with sequential numbering and AgentDB registration