From harness-claude
Implements idempotency pattern for safe retries on non-idempotent API operations (POST/PATCH), payments, and message queues using Idempotency-Key headers, Redis storage, TTL, and locks to prevent duplicates.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Ensure safe retries by making operations produce the same result regardless of how many times they execute
Implements idempotency keys for safe operation retries without duplicates in payments, APIs with retries, and distributed transactions. Includes Express middleware, database, Stripe-style, and message queue patterns.
Implements idempotent API operations with keys, Redis response caching, and DB constraints for safe retries in payments, webhooks, or duplicate processing.
Implements idempotency keys with Redis locks/caches for APIs and DB unique constraints for events to safely handle duplicate deliveries in payments, records, and notifications.
Share bugs, ideas, or general feedback.
Ensure safe retries by making operations produce the same result regardless of how many times they execute
Idempotency-Key header on non-idempotent endpoints (POST, PATCH). The client generates a unique key per logical operation.// middleware/idempotency.ts
interface StoredResponse {
statusCode: number;
body: unknown;
headers: Record<string, string>;
createdAt: number;
}
export class IdempotencyStore {
constructor(
private redis: Redis,
private ttlSeconds: number = 86400 // 24 hours
) {}
async check(key: string): Promise<StoredResponse | null> {
const data = await this.redis.get(`idem:${key}`);
return data ? JSON.parse(data) : null;
}
async lock(key: string): Promise<boolean> {
// Set NX — only succeeds if key does not exist
const result = await this.redis.set(`idem:lock:${key}`, '1', 'EX', 60, 'NX');
return result === 'OK';
}
async store(key: string, response: StoredResponse): Promise<void> {
await this.redis.setex(`idem:${key}`, this.ttlSeconds, JSON.stringify(response));
await this.redis.del(`idem:lock:${key}`);
}
async unlock(key: string): Promise<void> {
await this.redis.del(`idem:lock:${key}`);
}
}
// Express middleware
export function idempotencyMiddleware(store: IdempotencyStore) {
return async (req: Request, res: Response, next: NextFunction) => {
const key = req.headers['idempotency-key'] as string;
if (!key) return next(); // No key = no idempotency protection
// Check for cached response
const cached = await store.check(key);
if (cached) {
Object.entries(cached.headers).forEach(([k, v]) => res.setHeader(k, v));
return res.status(cached.statusCode).json(cached.body);
}
// Acquire lock to prevent concurrent processing
const locked = await store.lock(key);
if (!locked) {
return res.status(409).json({ error: 'Request is being processed' });
}
// Intercept the response to store it
const originalJson = res.json.bind(res);
res.json = (body: unknown) => {
store.store(key, {
statusCode: res.statusCode,
body,
headers: { 'content-type': 'application/json' },
createdAt: Date.now(),
});
return originalJson(body);
};
next();
};
}
// Client-side usage
const idempotencyKey = crypto.randomUUID();
const response = await fetch('/api/payments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify({ amount: 1000, currency: 'usd' }),
});
// Safe to retry with the same key — will get the same response
Naturally idempotent operations: GET, PUT, DELETE are idempotent by HTTP semantics. PUT /users/123 { name: "Alice" } always produces the same result. POST is not naturally idempotent — creating a resource twice creates two resources.
Database-level idempotency: Use unique constraints and upserts:
-- Instead of INSERT (which fails on duplicate)
INSERT INTO orders (idempotency_key, user_id, amount)
VALUES ($1, $2, $3)
ON CONFLICT (idempotency_key) DO NOTHING
RETURNING *;
Message deduplication:
async function processMessage(message: QueueMessage): Promise<void> {
const messageId = message.id;
const processed = await redis.set(`msg:${messageId}`, '1', 'EX', 3600, 'NX');
if (!processed) {
console.log(`Duplicate message ${messageId}, skipping`);
return;
}
await handleMessage(message.body);
}
Key generation strategies:
Edge cases:
https://stripe.com/docs/api/idempotent_requests