From harness-claude
Implements configurable retry strategies with exponential backoff and jitter for transient failures in network requests, database connections, and rate-limited APIs. Includes TypeScript utility function.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Handle transient failures with configurable retry strategies, exponential backoff, and jitter
Guides API retry strategies: classifies transient vs permanent errors, emits Retry-After headers, implements exponential backoff with jitter, ensures idempotency. Use for rate-limiting, 429/503 responses, client SDKs.
Generates PHP 8.4 retry pattern infrastructure with exponential backoff, jitter, configurable strategies for transient failures in APIs, databases, and queues. Includes unit tests.
Implements Python resilience patterns: retries with tenacity, exponential backoff, jitter, timeouts, and decorators. For fault-tolerant services handling transient failures and network issues.
Share bugs, ideas, or general feedback.
Handle transient failures with configurable retry strategies, exponential backoff, and jitter
delay = baseDelay * 2^attempt. This prevents thundering herd.delay = baseDelay * 2^attempt * (0.5 + random()). This spreads retry storms.// utils/retry.ts
interface RetryOptions {
maxAttempts: number;
baseDelay: number;
maxDelay: number;
shouldRetry?: (error: unknown, attempt: number) => boolean;
onRetry?: (error: unknown, attempt: number, delay: number) => void;
}
const DEFAULT_OPTIONS: RetryOptions = {
maxAttempts: 3,
baseDelay: 1000,
maxDelay: 30000,
shouldRetry: () => true,
};
export async function withRetry<T>(
fn: () => Promise<T>,
options: Partial<RetryOptions> = {}
): Promise<T> {
const opts = { ...DEFAULT_OPTIONS, ...options };
let lastError: unknown;
for (let attempt = 0; attempt < opts.maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (attempt === opts.maxAttempts - 1) break;
if (!opts.shouldRetry!(error, attempt)) break;
// Exponential backoff with full jitter
const exponentialDelay = opts.baseDelay * Math.pow(2, attempt);
const jitter = Math.random();
const delay = Math.min(exponentialDelay * jitter, opts.maxDelay);
opts.onRetry?.(error, attempt + 1, delay);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
throw lastError;
}
// Usage
import { withRetry } from './utils/retry';
const user = await withRetry(
() =>
fetch('/api/users/123').then((r) => {
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.json();
}),
{
maxAttempts: 3,
baseDelay: 1000,
shouldRetry: (error) => {
if (error instanceof Error && error.message.includes('HTTP 4')) return false;
return true; // Retry 5xx and network errors
},
onRetry: (error, attempt, delay) => {
console.warn(`Retry ${attempt} after ${delay}ms: ${error}`);
},
}
);
Backoff strategies:
delay = baseDelay * attempt. Gentle ramp-up.delay = baseDelay * 2^attempt. Standard for APIs.Jitter types:
random(0, baseDelay * 2^attempt) — most spread, lowest contentionbaseDelay * 2^attempt / 2 + random(0, baseDelay * 2^attempt / 2) — guaranteed minimum waitmin(maxDelay, random(baseDelay, prevDelay * 3)) — Amazon recommendationRetry-After header: Some APIs return Retry-After with 429 or 503 responses. Always respect this header over your calculated backoff.
What NOT to retry:
Libraries: p-retry, async-retry, cockatiel (composable policies), axios-retry.
https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/