System Design (50 Qs)•Part 2: Real-World High-Scale Architecture Problems (11 - 25)
Design an Idempotent Payment System (Stripe / Checkout).
In Simple Words: Ensure that double-clicks, network timeouts, or retried API calls NEVER charge a customer twice or corrupt bank transaction balances.
Idempotency Key Architecture:
- Client generates a UUIDv4 Idempotency Key in request header (
Idempotency-Key: c9d721...). - Payment gateway acquires a distributed lock in Redis for that key.
- If the key exists with a completed status, return the cached previous HTTP response immediately without touching payment processors.
- Execute financial transaction within a strict database transaction.
typescript
export async function processPaymentWithIdempotency(
idempotencyKey: string,
chargeData: { userId: string; amount: number },
redis: any,
db: any
): Promise<{ status: string; transactionId: string }> {
const cacheKey = `idemp:${idempotencyKey}`;
// 1. Check if already processed
const cachedResponse = await redis.get(cacheKey);
if (cachedResponse) {
return JSON.parse(cachedResponse);
}
// 2. Acquire 30-second lock
const locked = await redis.set(`lock:${cacheKey}`, '1', 'NX', 'EX', 30);
if (!locked) {
throw new Error('Concurrent request with identical idempotency key in progress');
}
try {
// 3. Execute financial deduction in database
const result = await db.executeTransaction(chargeData);
await redis.set(cacheKey, JSON.stringify(result), 'EX', 86400 * 7); // Cache for 7 days
return result;
} finally {
await redis.del(`lock:${cacheKey}`);
}
}