Implement Exa rate limiting, backoff, and idempotency patterns. Use when handling rate limit errors, implementing retry logic, or optimizing API request throughput for Exa. Trigger with phrases like "exa rate limit", "exa throttling", "exa 429", "exa retry", "exa backoff".
Implements exponential backoff and idempotency for Exa API calls to handle rate limits and retries.
/plugin marketplace add jeremylongshore/claude-code-plugins-plus-skills/plugin install exa-pack@claude-code-plugins-plusThis skill is limited to using the following tools:
Handle Exa rate limits gracefully with exponential backoff and idempotency.
| Tier | Requests/min | Requests/day | Burst |
|---|---|---|---|
| Free | 60 | 1,000 | 10 |
| Pro | 300 | 10,000 | 50 |
| Enterprise | 1,000 | 100,000 | 200 |
async function withExponentialBackoff<T>(
operation: () => Promise<T>,
config = { maxRetries: 5, baseDelayMs: 1000, maxDelayMs: 32000, jitterMs: 500 }
): Promise<T> {
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
try {
return await operation();
} catch (error: any) {
if (attempt === config.maxRetries) throw error;
const status = error.status || error.response?.status;
if (status !== 429 && (status < 500 || status >= 600)) throw error;
// Exponential delay with jitter to prevent thundering herd
const exponentialDelay = config.baseDelayMs * Math.pow(2, attempt);
const jitter = Math.random() * config.jitterMs;
const delay = Math.min(exponentialDelay + jitter, config.maxDelayMs);
console.log(`Rate limited. Retrying in ${delay.toFixed(0)}ms...`);
await new Promise(r => setTimeout(r, delay));
}
}
throw new Error('Unreachable');
}
import { v4 as uuidv4 } from 'uuid';
import crypto from 'crypto';
// Generate deterministic key from operation params (for safe retries)
function generateIdempotencyKey(operation: string, params: Record<string, any>): string {
const data = JSON.stringify({ operation, params });
return crypto.createHash('sha256').update(data).digest('hex');
}
async function idempotentRequest<T>(
client: ExaClient,
params: Record<string, any>,
idempotencyKey?: string // Pass existing key for retries
): Promise<T> {
// Use provided key (for retries) or generate deterministic key from params
const key = idempotencyKey || generateIdempotencyKey(params.method || 'POST', params);
return client.request({
...params,
headers: { 'Idempotency-Key': key, ...params.headers },
});
}
| Header | Description | Action |
|---|---|---|
| X-RateLimit-Limit | Max requests | Monitor usage |
| X-RateLimit-Remaining | Remaining requests | Throttle if low |
| X-RateLimit-Reset | Reset timestamp | Wait until reset |
| Retry-After | Seconds to wait | Honor this value |
import PQueue from 'p-queue';
const queue = new PQueue({
concurrency: 5,
interval: 1000,
intervalCap: 10,
});
async function queuedRequest<T>(operation: () => Promise<T>): Promise<T> {
return queue.add(operation);
}
class RateLimitMonitor {
private remaining: number = 60;
private resetAt: Date = new Date();
updateFromHeaders(headers: Headers) {
this.remaining = parseInt(headers.get('X-RateLimit-Remaining') || '60');
const resetTimestamp = headers.get('X-RateLimit-Reset');
if (resetTimestamp) {
this.resetAt = new Date(parseInt(resetTimestamp) * 1000);
}
}
shouldThrottle(): boolean {
// Only throttle if low remaining AND reset hasn't happened yet
return this.remaining < 5 && new Date() < this.resetAt;
}
getWaitTime(): number {
return Math.max(0, this.resetAt.getTime() - Date.now());
}
}
For security configuration, see exa-security-basics.
Expert guidance for Next.js Cache Components and Partial Prerendering (PPR). **PROACTIVE ACTIVATION**: Use this skill automatically when working in Next.js projects that have `cacheComponents: true` in their next.config.ts/next.config.js. When this config is detected, proactively apply Cache Components patterns and best practices to all React Server Component implementations. **DETECTION**: At the start of a session in a Next.js project, check for `cacheComponents: true` in next.config. If enabled, this skill's patterns should guide all component authoring, data fetching, and caching decisions. **USE CASES**: Implementing 'use cache' directive, configuring cache lifetimes with cacheLife(), tagging cached data with cacheTag(), invalidating caches with updateTag()/revalidateTag(), optimizing static vs dynamic content boundaries, debugging cache issues, and reviewing Cache Component implementations.