Problems / Real world, hard
A payments API on its first servers: no charge status cache, and the charges API, status API, fraud scoring, ledger and webhook delivery workers at an eighth of their real size. 1,500 requests a second: 70% charges that must never apply twice, 30% status checks. About half of all requests fail.
Unlock it once for 25 credits; everything inside it is free (runs, changes, Submit, results, hints). Sign in with Google to start; new accounts get free credits.
Grow it into the real architecture: every goal must hold at 1,500 requests a second. You may add components, connect them and resize anything.
Like a coding problem, a solution has to pass every case, not just the one it was built for. Submit in the lab runs all 5; 1 of them are hidden until then.
1,500 requests a second for 20 seconds: 70% charge (writes), 30% status (reads).
What each component does in this design, and what calls it. The simulator mimics each one from these settings.
| Component | Its job here | Settings |
|---|---|---|
| WAFWAF | Traffic enters here.Calls API gateway (API keys, idempotency keys).A WAF inspects HTTP requests for attacks such as SQL injection and cross-site scripting. | 100000 slots |
| API gateway (API keys, idempotency keys)API gateway | WAF forwards to it.Calls Fraud scoring (Radar), Status API.Gateways centralise auth, rate limits and routing so each service does not reimplement them. | 50000 slots · 600,000 calls/min |
| Fraud scoring (Radar)Fraud detection | API gateway (API keys, idempotency keys) forwards to it for /charge.Calls Charges API.Fraud models score each transaction in milliseconds from behaviour and history. | 12500 slots |
| Charges APIApp service | Fraud scoring (Radar) forwards to it.Calls Ledger (double-entry), Card network (acquirer A), Payment events (outbox → Kafka) (publishes).Little's law: throughput ≈ concurrency ÷ latency. 200 slots at 50 ms serve about 4,000 req/s. | 1 replicas × 100 slots · timeout 8.0 s |
| Ledger (double-entry)Ledger database | Charges API calls it. Status API calls it for reads.Ledgers are append-only: a correction is a new entry, never an edit. | 50 slots |
| Card network (acquirer A)Payment gateway | Charges API calls it.Calls Card network (acquirer B) (fallback).Payment providers accept an idempotency key so a retried charge is not taken twice. | 250 slots |
| Card network (acquirer B)Payment gateway | Card network (acquirer A) falls back to it on failure.Payment providers accept an idempotency key so a retried charge is not taken twice. | 250 slots |
| Payment events (outbox → Kafka)Event stream | Charges API publishes to it.Calls Webhook delivery workers.Kafka keeps order only within a partition, so the partition key decides what stays in sequence. | 4 partitions · retention 600 s |
| Webhook delivery workersWorker | Payment events (outbox → Kafka) consumes from it.Calls Merchant webhook endpoints.Queues deliver at least once, so a worker can see the same message twice. | 128 concurrent jobs |
| Merchant webhook endpointsExternal API (mock) | Webhook delivery workers calls it.Third-party APIs have their own rate limits and outages that you cannot fix. | 500 slots · 1,250,000 calls/min |
| Status APIApp service | API gateway (API keys, idempotency keys) forwards to it for /status.Calls Ledger (double-entry).Little's law: throughput ≈ concurrency ÷ latency. 200 slots at 50 ms serve about 4,000 req/s. | 1 replicas × 100 slots · timeout 1.0 s |