Skip to content
Forward Deployed

Forward Deployed
Lessons and contents
Distributed executionLesson 3 of 5
5 lessons
Learn

Distributed execution: observe and experiment

Source
From the Staff AI System Design course
By
Sourav Banerjee
Last updated
4 Nov 2026

Report an issue

Request Walkthrough

The offline walkthrough exposes success, worker crash before external effects, and unknown external outcome. At each step read the owner, input, durable output, and possible failure before advancing.

Interactive lab: Distributed execution: request walkthrough and lab. Open full screen (opens in a new tab)
DiagramDiagram

Sequence diagram. Acceptance commits before 202; completion is a later event. Redelivery never grants a stale worker authority to overwrite newer state.

Step Input and responsible component Output and possible failure
Accept API receives trusted scope, key, and payload Queue row commits; unavailable DB means no acceptance success
Claim Worker asks durable Queue for eligible work Epoch/lease commit; racing worker gets no active duplicate claim
Execute Worker reads immutable input and budgets Bounded checkpoint/tool result; unsafe external ambiguity is preserved
Recover Queue examines expiry and external-start marker Pure work may redeliver; started external work becomes unknown
Complete Worker submits result with current epoch Completed commit or rejection of stale/expired authority
Inspect API reads scoped job state Saved output or explicit queued/leased/dead/unknown state

Calculate the Required Concurrency

At six jobs/minute and 20 seconds/job, arrival rate is 0.1 jobs/s. The required average in-flight work in a stable regime is λW = 0.1 × 20 = 2 jobs. Two workers each able to finish one job in 20 seconds provide exactly six jobs/minute with no nominal headroom. Choose three for the illustrative discussion: capacity becomes nine jobs/minute and utilisation is about 67%, before dependency quotas or runtime variability. These are workload calculations, not measurements of the Python fixture.

If 12 jobs arrive together and three independent workers take exactly 20 seconds/job, four waves finish at 20, 40, 60, and 80 seconds. This ignores claim/commit overhead and external contention. A 90-second job deadline leaves only 10 seconds of margin for the last wave. A 30-second browser timeout should not govern this longer job’s lifetime; return the durable identifier and poll at a bounded interval with backoff instead.

Assuming five state writes per job, six jobs/minute yields about 30 writes/minute, or 0.5 writes/s, before polling and retries. One hundred clients polling every second would add 100 reads/s even when the worker throughput is small. Include polling load in capacity estimates; do not fix a status-query bottleneck by adding more generation workers.

Lab: Crash Position Changes Recovery

Open the lease experiment. Its two controls are the lease interval (5–30 logical seconds) and crash position. A worker is assumed to stop at time zero; no real time elapses and no provider is called.

Case Lease Failure position Expected result
Healthy 10 s None Completed; no replacement attempt
Recoverable crash 10 s Before an external effect Earliest replacement at 10 s; pure work redelivers; stale completion rejected
Longer lease 30 s Before an external effect Earliest replacement at 30 s; slower failure recovery
Ambiguous call 10 s After external-start marker Unknown; no new worker attempt authorised automatically

An actual worker that lives longer than its lease needs a bounded heartbeat/renewal policy. This slice instead rejects expired completions and uses explicit logical-clock experiments. A shorter lease can improve recovery time but can create false takeovers during pauses. The epoch protects state writes, not duplicate billing.

Run the code lab

Run this stage's Python lab in your terminal to see each idea in the stage hold. It needs Python 3.10 or later and nothing else: the standard library and SQLite only.

File What it is
jobs.py Lab code: read this first
test_jobs.py Tests: one test per behaviour this stage teaches

From the root of your local clone of the repository, run:

python3 10_AI_System_Design/stages/02-distributed-execution/labs/test_jobs.py -v

-v prints one line per test, and each test name states one behaviour. Read a test, change one value in the lab code, predict which test fails, and run it again.

The tests create a temporary database, instantiate/recreate worker stores, race two claimers, expire a lease, attempt a stale completion, record an external start, exhaust safe retries, enforce a deadline, and reject an unapproved tool. They exercise real SQLite commits with a simulated clock. They do not start an HTTP job endpoint or run a network broker. Inspect jobs.py, change a lease/deadline, and explain which test should fail before rerunning it.

Checkpoint 2: Lease Expiry Is Not Proof of Failure

A model call started, its worker stopped answering, and its lease expired. May the replacement call the model immediately?

Answer before revealing

No. A timeout or dead worker does not prove the provider stopped. The job enters unknown and requires reconciliation. Automatic redelivery is appropriate only for the defined safe portion of this exercise; an epoch fences local writes, not remote execution.

Key Takeaways

  • At six jobs a minute and 20 seconds each, Little's law gives two jobs in flight. Two workers supply exactly six a minute with no headroom, while three give nine a minute at about 67% utilisation.
  • Twelve simultaneous jobs on three workers finish in waves at 20, 40, 60 and 80 seconds, leaving 10 seconds of margin under a 90-second deadline. Return the job identifier and poll with backoff rather than tying the job to a 30-second browser timeout.
  • Polling is load too. Five state writes per job give about 0.5 writes a second, but 100 clients polling every second add 100 reads a second, which more generation workers cannot fix.
  • A shorter lease speeds recovery but risks false takeovers during pauses. A crash before an external effect allows redelivery once the lease expires, while a crash after the external-start marker leaves the job unknown.

Rate your confidence and keep notes on the module page.