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.
1Design a nightly pipeline that loads delivery files from a partner, which arrive anywhere between 03:00 and 11:00. 300 pipelines depend on them. What do you build?Show the answer

Estimate

If each of 300 pipelines holds a slot through an average wait of 4 hours, many hundreds of slots sit occupied by waiting (). No sensible pool covers that.

Design

that release their slots and register with one shared poller checking every 5 minutes (an average detection delay of 2.5 minutes). Ask the partner for a success marker and a manifest with the expected file count. Add a timeout, say at 14:00, that raises an alert rather than guessing.

Polling cost

The shared poller makes , instead of 300 × 240 = 72,000.

Trade-offs

The shared poller is a new single point of failure, so run two. A partner that forgets the marker is caught by the timeout alert. Add an external on the final publish.

Read moreSensors hold slotsPolling costThe cleanest impossibilityThe run that never started

2A daily_sales load task crashed after writing half its rows. The orchestrator retried it, and now the day's revenue is doubled. How do you prevent this class of bug?Show the answer

Diagnose

The task appended. A after a partial append leaves duplicates, with no key to remove them by.

Fix

Address the output by the interval: replace the append with an overwrite of the day (delete the and insert, in one transaction) or a merge on the business key. Ban now() and unversioned lookups. Add write–audit–publish: write to a staging path named after the attempt, assert row count and key uniqueness, then publish with one pointer swap, so a crash leaves nothing visible.

Cost

Rewriting a whole partition amplifies writes by the ratio of partition to rows changed, plus a staging copy and the time to run the assertions.

Test it

In CI, kill the task at random points and check that the final table equals one clean run.

Read moreThe one requirementThe priceCompletion verification

3The orchestrator's host died on Friday evening, and nobody noticed until Monday. Make sure that cannot happen again.Show the answer

Diagnose

A run that never starts emits no failure, and inside the are down along with it.

Build

An external dead-man's switch: the last task of each critical pipeline pings an independent service, on another machine with another alert channel, which expects the ping by a deadline (say 06:30) and pages when it is missing. Check the data, that the latest partition is yesterday's, not just the task.

For consumers

A staleness banner, or serving the last good partition.

Lower the odds

Run the as a highly available pair with . The monitor is a second system with its own availability, so keep it very simple, and have it send its own to a third place.

Read moreWhy the orchestrator cannot watch itselfTask SLA versus data SLAScheduler self-durability

4After a network partition, two workers may be running the same task. Walk through the options.Show the answer

The impossibility

You cannot tell a dead worker from a slow one.

Options

  1. Assume dead and relaunch: two writers may tear the partition.
  2. Assume alive and wait: the pipeline may stall indefinitely, with no alert.
  3. Fence: each attempt carries an increasing token, and the rejects stale ones. That needs the sink's cooperation, which object stores and JDBC targets usually do not give.

Practical design

launch; a timeout based on the task's distribution of durations; and write–audit–publish with a on the table pointer, using the attempt number as the token, so a stale attempt loses at publish time even if raw writes cannot be fenced.

Be clear

Exactly-once is not available.

Read moreThe unknown stateFencingThe honest part

5Marketing's pipeline depends on tables owned by three other teams, and last month a renamed folder broke it for two days. Propose a design.Show the answer

Diagnose

The technical cost is tiny; the contract between teams is what is expensive.

Design

Replace of output paths with dataset declarations in a shared catalog: each table has an owner, a name, a convention for signalling completion, and a rule for notice of changes (say 14 days). Producers publish an event when a partition is ready; consumers declare the dataset names they read, keep an hourly poll as a fallback for lost events, and alert externally on freshness.

Trade-offs

A shared namespace needs an owner and a process, not just a deployment. Dataset declarations can be coarser than the real partition dependency and cause spurious wake-ups, so declare datasets per partition where the store allows. Declarations are still unvalidated, so capture at run time to find undeclared reads.

Principle

Orchestrate inside each team; use events and datasets between teams.

Read moreCross-DAG and cross-system dependenciesDataset-aware scheduling

6Plan a two-year backfill of a table after a logic fix, without hurting production. Each day's interval takes 10 minutes.Show the answer

Are intervals independent?

If the table carries cumulative state, the must run in order: = 7,300 minutes, about 5 days, and no amount of capacity helps.

If they are independent

Run them in parallel in a separate pool, bounded by what the warehouse can spare: with 2 slots, 730 ÷ 2 × 10 = 3,650 minutes, about 61 hours; with 8 slots, about 15 hours.

Design

Turn off automatic catch-up, so the backfill is an explicit action. Overwrite idempotently by key, with write–audit–publish per partition, so a failure leaves the old data visible. Stamp every rewritten partition with the new code version, so consumers can see where old and new logic mix.

Say the risk

Until the backfill finishes, rows from the new code mean something different from the old rows.

Read moreBackfills, catchup and versioningBlast radiusVersioning: the unsolved part

7A product team wants an approval workflow (manager approval, then payment, then notification, undoing the payment if notification fails) and suggests building it as an Airflow-style DAG. Do you agree?Show the answer

Not for this

The state between steps is small, and the control flow has waits, loops and compensation, which suits . A task would hold a slot during the human wait (and a deployment will kill that process long before the manager answers), has no natural compensation, and retries coarsely.

Recommend

A durable-execution engine: the wait is a row, not a running process; each activity retries on its own; the compensating refund is another activity in the log. Add a timeout with a stated default (fail closed, for payments), an immutable approval record (who, when, which version of the request), and pinned parameters.

The cost

requires deterministic code (no direct now() or network calls), and code changes need explicit versioning.

Keep

Bulk data pipelines as DAGs: their state cannot live in workflow variables.

Read moreDurable executionHuman-in-the-loop stepsReplay must be deterministic

8Your critical pipeline has top priority in the orchestrator but still misses its deadline. Diagnose it.Show the answer

Hypothesis

The delay is downstream. Measure time spent queued in the warehouse or Spark cluster against time in the orchestrator. If, say, 25 of 28 minutes are spent in the engine's queue, orchestrator priority is decorative, since it only governs admission.

Fix

A reserved queue or capacity class in the engine for this pipeline, with a way for the task to name its queue; separate pools in the orchestrator so backfills are not starved; and fewer low-priority queries running during the critical window.

Other candidates

Pool limits set too low, a long wait in an upstream sensor, or a delay in the scheduler parsing workflow files.

Trade-off

Reserved capacity lowers , since it sits idle outside the critical window: the price of isolation.

Read moreThe last queue winsStarvationPools