Implement Vercel reliability patterns including circuit breakers, idempotency, and graceful degradation. Use when building fault-tolerant Vercel integrations, implementing retry strategies, or adding resilience to production Vercel services. Trigger with phrases like "vercel reliability", "vercel circuit breaker", "vercel idempotent", "vercel resilience", "vercel fallback", "vercel bulkhead".
/plugin marketplace add jeremylongshore/claude-code-plugins-plus-skills/plugin install vercel-pack@claude-code-plugins-plusThis skill is limited to using the following tools:
Production-grade reliability patterns for Vercel integrations.
import CircuitBreaker from 'opossum';
const vercelBreaker = new CircuitBreaker(
async (operation: () => Promise<any>) => operation(),
{
timeout: 10000,
errorThresholdPercentage: 50,
resetTimeout: 30000,
volumeThreshold: 10,
}
);
// Events
vercelBreaker.on('open', () => {
console.warn('Vercel circuit OPEN - requests failing fast');
alertOps('Vercel circuit breaker opened');
});
vercelBreaker.on('halfOpen', () => {
console.info('Vercel circuit HALF-OPEN - testing recovery');
});
vercelBreaker.on('close', () => {
console.info('Vercel circuit CLOSED - normal operation');
});
// Usage
async function safeVercelCall<T>(fn: () => Promise<T>): Promise<T> {
return vercelBreaker.fire(fn);
}
import { v4 as uuidv4 } from 'uuid';
import crypto from 'crypto';
// Generate deterministic idempotency key from input
function generateIdempotencyKey(
operation: string,
params: Record<string, any>
): string {
const data = JSON.stringify({ operation, params });
return crypto.createHash('sha256').update(data).digest('hex');
}
// Or use random key with storage
class IdempotencyManager {
private store: Map<string, { key: string; expiresAt: Date }> = new Map();
getOrCreate(operationId: string): string {
const existing = this.store.get(operationId);
if (existing && existing.expiresAt > new Date()) {
return existing.key;
}
const key = uuidv4();
this.store.set(operationId, {
key,
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000),
});
return key;
}
}
import PQueue from 'p-queue';
// Separate queues for different operations
const vercelQueues = {
critical: new PQueue({ concurrency: 10 }),
normal: new PQueue({ concurrency: 5 }),
bulk: new PQueue({ concurrency: 2 }),
};
async function prioritizedVercelCall<T>(
priority: 'critical' | 'normal' | 'bulk',
fn: () => Promise<T>
): Promise<T> {
return vercelQueues[priority].add(fn);
}
// Usage
await prioritizedVercelCall('critical', () =>
vercelClient.processPayment(order)
);
await prioritizedVercelCall('bulk', () =>
vercelClient.syncCatalog(products)
);
const TIMEOUT_CONFIG = {
connect: 5000, // Initial connection
request: 30000, // Standard requests
upload: 120000, // File uploads
longPoll: 300000, // Webhook long-polling
};
async function timedoutVercelCall<T>(
operation: 'connect' | 'request' | 'upload' | 'longPoll',
fn: () => Promise<T>
): Promise<T> {
const timeout = TIMEOUT_CONFIG[operation];
return Promise.race([
fn(),
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error(`Vercel ${operation} timeout`)), timeout)
),
]);
}
interface VercelFallback {
enabled: boolean;
data: any;
staleness: 'fresh' | 'stale' | 'very_stale';
}
async function withVercelFallback<T>(
fn: () => Promise<T>,
fallbackFn: () => Promise<T>
): Promise<{ data: T; fallback: boolean }> {
try {
const data = await fn();
// Update cache for future fallback
await updateFallbackCache(data);
return { data, fallback: false };
} catch (error) {
console.warn('Vercel failed, using fallback:', error.message);
const data = await fallbackFn();
return { data, fallback: true };
}
}
interface DeadLetterEntry {
id: string;
operation: string;
payload: any;
error: string;
attempts: number;
lastAttempt: Date;
}
class VercelDeadLetterQueue {
private queue: DeadLetterEntry[] = [];
add(entry: Omit<DeadLetterEntry, 'id' | 'lastAttempt'>): void {
this.queue.push({
...entry,
id: uuidv4(),
lastAttempt: new Date(),
});
}
async processOne(): Promise<boolean> {
const entry = this.queue.shift();
if (!entry) return false;
try {
await vercelClient[entry.operation](entry.payload);
console.log(`DLQ: Successfully reprocessed ${entry.id}`);
return true;
} catch (error) {
entry.attempts++;
entry.lastAttempt = new Date();
if (entry.attempts < 5) {
this.queue.push(entry);
} else {
console.error(`DLQ: Giving up on ${entry.id} after 5 attempts`);
await alertOnPermanentFailure(entry);
}
return false;
}
}
}
type HealthStatus = 'healthy' | 'degraded' | 'unhealthy';
async function vercelHealthCheck(): Promise<{
status: HealthStatus;
details: Record<string, any>;
}> {
const checks = {
api: await checkApiConnectivity(),
circuitBreaker: vercelBreaker.stats(),
dlqSize: deadLetterQueue.size(),
};
const status: HealthStatus =
!checks.api.connected ? 'unhealthy' :
checks.circuitBreaker.state === 'open' ? 'degraded' :
checks.dlqSize > 100 ? 'degraded' :
'healthy';
return { status, details: checks };
}
Wrap Vercel calls with circuit breaker.
Generate deterministic keys for operations.
Separate queues for different priorities.
Handle permanent failures gracefully.
| Issue | Cause | Solution |
|---|---|---|
| Circuit stays open | Threshold too low | Adjust error percentage |
| Duplicate operations | Missing idempotency | Add idempotency key |
| Queue full | Rate too high | Increase concurrency |
| DLQ growing | Persistent failures | Investigate root cause |
const state = vercelBreaker.stats().state;
console.log('Vercel circuit:', state);
For policy enforcement, see vercel-policy-guardrails.