Skip to main content

Error recovery

Graceful error handling patterns.

Retry with exponential backoff

import { Mappa, RateLimitError, ApiError } from "@mappa-ai/mappa-node";

const mappa = new Mappa({
apiKey: process.env.MAPPA_API_KEY!,
});

async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelay = 1000
): Promise<T> {
let lastError: Error;

for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;

// Don't retry client errors (except rate limits)
if (error instanceof ApiError && error.status < 500) {
if (!(error instanceof RateLimitError)) {
throw error;
}
}

// Calculate delay
let delay = baseDelay * Math.pow(2, attempt);

// Use Retry-After header if available
if (error instanceof RateLimitError && error.retryAfterMs) {
delay = error.retryAfterMs;
}

console.warn(`Attempt ${attempt + 1} failed, retrying in ${delay}ms`);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}

throw lastError!;
}

// Usage
const report = await withRetry(() =>
mappa.reports.generateFromUrl({
url: "https://example.com/recording.mp3",
output: { template: "general_report" },
})
);

Circuit breaker pattern

class CircuitBreaker {
private failures = 0;
private lastFailure = 0;
private readonly threshold = 5;
private readonly resetTimeout = 60000;

async execute<T>(fn: () => Promise<T>): Promise<T> {
if (this.isOpen()) {
throw new Error("Circuit breaker is open");
}

try {
const result = await fn();
this.reset();
return result;
} catch (error) {
this.recordFailure();
throw error;
}
}

private isOpen(): boolean {
if (this.failures >= this.threshold) {
if (Date.now() - this.lastFailure > this.resetTimeout) {
this.reset();
return false;
}
return true;
}
return false;
}

private recordFailure(): void {
this.failures++;
this.lastFailure = Date.now();
}

private reset(): void {
this.failures = 0;
}
}

const breaker = new CircuitBreaker();

const report = await breaker.execute(() =>
mappa.reports.generateFromUrl({
url: "https://example.com/recording.mp3",
output: { template: "general_report" },
})
);