Skip to content
About
Main content

Scenarios

Longer problems, like those in senior system design interviews. A strong answer estimates with numbers first, names the mechanism, then recommends a fix and says what it costs.

Try each one before you open the answer.
1A nightly job has 10,000 tasks, and on every run at least some of them fail. How do you make it finish reliably?Show the answer

Accept

At this scale, some failure is certain. Design for it.

Design

, for example up to three attempts. Blacklist bad nodes, with a decay time and a quota (at most about 10% of nodes), so failures stay independent rather than repeating on the same machine. Keep shuffle files, so a lost partition does not force re-running a whole stage.

Trade-off

too many nodes shrinks capacity.

Read moreTask re-execution and blacklistingThe cost is the fan-in

2A pipeline normally runs at 90% utilization and was down for 3 hours. How long until it catches up, and what should you change?Show the answer

Estimate

Its spare capacity is 10% of maximum throughput, a ninth of the arrival rate, so .

Change

To recover from a 3-hour outage in 1 hour, capacity must be (3 + 1) × the arrival rate, so the pipeline should run at about 25% utilization at peak.

The principle

Utilization should be set by the recovery budget, not the latency budget. The cost is more machines.

Read moreThe catch-up condition

3Should the primary database fail over automatically?Show the answer

Compare

With one real failure a year saving 20 minutes, and four false alarms a year each costing 180 minutes, manual failover wins.

Recommend

Keep automatic failover for stateless services and read .

Either way

Enforce fencing at the storage layer with an number, and expect to lose data equal to the replication lag at the worst moment.

Read moreAutomatic or manual is arithmeticFailover converts RTO into RPO

4Replaying yesterday's data gives different totals from the original run. How do you diagnose and fix it?Show the answer

Diagnose

Look for non-determinism: calls to now(), random numbers, lookup tables that have since changed, iteration over unordered collections.

Fix

Carry event time through the log instead of reading the clock, and version reference data by date.

Prevent

Add a test that runs the job twice on the same input and compares output hashes.

Read moreDeterminism is the precondition

5A service charges a card through a payment API and writes to a database. Which recovery mechanism applies to each step, and where should the irreversible step go?Show the answer

Classify

The database write can be rolled back, or protected with a . The card charge is visible to the outside world and cannot be undone, only compensated by a refund.

Design

Restructure so the single irreversible act comes last. Record the intent first, then act, and run a recovery scan that reconciles intents left unfinished by a crash.

Read moreThe nine ways to recoverWrite-ahead intentUndo stops at the first visible effect

6Design the payment step so that a retry can never charge a customer twice.Show the answer

Design

Use the order ID as the , generated by the client and sent on the first attempt and every retry. The provider, or your own table, stores key → outcome, committed in the same transaction as the charge, and returns the stored outcome on a repeat.

Check the window

If the provider keeps keys for 24 hours and your longest recovery has been 3 hours, the bet holds with margin. Write it in the runbook.

Without provider support

Keep your own table keyed by order ID, and add a reconciliation job against the provider's records.

Trade-off

Deduplication state grows without bound, hence the window: at 100,000 keys per second with 32-byte entries, one hour is about 11 GB.

Read moreImposed idempotenceDedup windows

7A Kafka-style consumer writes to PostgreSQL, and after crashes some events are counted twice. Fix it.Show the answer

Diagnose

The consumer's position lives in the broker and the effect lives in the database, so no order of committing the two is correct.

Fix

Store the in a database row, updated in the same transaction as the effect, and on startup seek to the stored offset. Fence writes by consumer generation, so a stale owner after a rebalance cannot write.

Failure modes

The consumer's position is now tied to one sink, and rebalances can race.

If the sink were an HTTP API

Use deterministic idempotency keys instead.

Read moreConsumer offsets and commit orderingOffset commits must be fenced

8A stream-processing job claims exactly-once, yet patients receive the same SMS twice. Explain.Show the answer

Explain

The engine's guarantee covers only its own state and its . Sending an SMS from user code is a side effect outside every , so it repeats when the job recovers.

Options

Send through an outbox with an idempotency key, if the SMS provider supports one. If not, accept and say so; or make the message harmless to repeat ("your results are ready" twice).

Decide

With the business owner.

Read moreThe exactly-once category error

9A transactional sink lost data after a 40-minute outage. Diagnose.Show the answer

Diagnose

The sink's for , say 15 minutes, was shorter than failure detection + restart + draining the backlog. The sink aborted the prepared transaction before the engine could commit it, and the data in it was lost.

Fix

Raise the timeout , and alert on the age of pending transactions.

Remember

Latency through such a sink is quantized to the .

Read moreThe prepared transaction has a timeoutLatency is quantized

10One malformed message blocked a partition all night. Design the policy for such messages.Show the answer

Count attempts durably

Keep the retry count in the message headers; a counter in memory resets on restart.

Classify at the source

A parse error is permanent; a refused connection is transient. That way a downstream outage does not quarantine good data.

Choose by data

For a ledger, stop the line and page someone. For a clickstream, skip the message to a .

Close the loop

Reconcile counts, or alert on dead-letter queue depth, with an owner.

Read morePoison pills and skip-and-logThe classifier is asymmetric

11For two data centres, choose between three full copies of the data and two copies plus a witness.Show the answer

The witness

It saves a third of the storage (2× instead of 3×) and gives the odd vote. But losing one site leaves a single copy for the hours of rebuild, and the witness must be in a third site, not inside either data site.

Recommend

Three full copies for critical data, such as patient records; the witness design for less critical data.

Read moreWitness replicasPlacement is the entire design

12A stream job keeps running totals per seller. After a failure and restart, the totals are slightly off. Why, and what would you change?Show the answer

Diagnose

State and input positions were most likely restored from different moments, or offsets are committed by a different mechanism from the state.

Fix

Checkpoint state and input positions together, with a barrier-based snapshot. Use aligned barriers if checkpoint size is the concern and unaligned if checkpoint time under backpressure is, and note that aligned checkpoints slow down exactly when the job is stressed. Use incremental checkpoints for large state, planning retention, since each checkpoint depends on the previous one.

External sinks

Use upserts, or a two-phase-commit sink whose transaction timeout exceeds the checkpoint interval.

Verify

Crash tests, and comparing the totals with a batch recomputation.

Read moreCheckpointsTwo-phase commit to an external sink

13Your service must send a legally required letter, as physical mail through a vendor's API, exactly once per event. The vendor has no idempotency support. Design it.Show the answer

Choose

Exactly-once is impossible for an external effect that cannot be deduplicated. Choose with the business owner: a duplicate letter is annoying and costs money; a missing one may be a legal breach. So choose at-least-once, with tight control of duplicates.

Design

The consumer upserts a row in pending_letters keyed by event_id, an idempotent intermediary. A separate sender records its intent ("about to send"), calls the vendor, then marks the row sent. Make the letter the last effect in the sequence.

After a crash

Rows left in "about to send" are known unknowns. Reconcile them against the vendor's report, or with a human check, before sending again. Monitor how many such rows exist.

Trade-off

An extra table and a small manual process, in exchange for ambiguity that is visible and bounded.

Read moreEffects outside the boundary (Fault Tolerance)