How do you show, in Thunk's artefacts and in the discussion, that you understand distributed systems?
The exam is a discussion of the project, after its artefacts pass a check. The professor looks for course concepts in the artefacts. Thunk is a good vehicle for this, because its one strong assumption, purity, turns several hard problems of the course into easy ones. Re-executing lost work is safe. Wrongly suspecting a slow node is harmless. Cached results never go stale. No agreement protocol is needed. Explaining why each problem becomes easy, in the course's own terms, is the clearest evidence of understanding. So is saying where Thunk still has limits.
From the course introduction (A0):
In practice: every design decision in the report should be named with the course vocabulary, justified by a course concept, and honest about its assumptions.
Thunk.Scheduler.Distributed. The owner of a piece is the only authority for its result.Programs are S-expressions; dc (divide and conquer) is the only parallel form. Solving a piece splits it, pushes the right half on the local deque and solves the left half. The right half is then taken back if nobody stole it, or awaited from the thief. A lost thief (crashed process or lost node, reported by a monitor) makes the owner solve the piece again. A language error is re-raised instead, because a deterministic program would fail again.
Around this core: a node joins a running cluster knowing a single seed and learns the other members by gossip, then starts stealing at once, even from a job already running. A dashboard node polls every worker's counters (deque length, steals, pieces evaluated and recovered) twice a second without evaluating anything. The demos (mergesort, word count, a ray-traced cube, a Mandelbrot set whose rows cost very different amounts of work) exercise the stealing.
| Chapter | Concept | In Thunk |
|---|---|---|
| 1 | distributed concurrent computing (S ≠ S′, T ≠ T′); transparency; decentralised algorithms; fallacies | Peers on different nodes, each with its own evaluators. “Which node solves each piece is up to the scheduler; the result is the same” is location and replication transparency for the programmer. No coordinator, following Raynal's point that only decentralised algorithms scale. The fallacies “the network is reliable” and “topology doesn't change” are exactly what monitors, re-execution and seed-plus-gossip membership address; joining at run time is openness. |
| 2 | no global clock; physical time only for intervals; happens-before | No clock synchronisation anywhere. Physical time enters only through failure detection (the BEAM's distribution heartbeat, a timeout). A piece's result happens-before the merge that uses it: the task tree is a causal structure. |
| 3 | code mobility; weak vs strong; receiver-initiated; resource binding | Pieces travel as data, and program definitions are fetched on demand by a thief that lacks them. This is weak mobility: no execution state moves, the piece restarts from its description. It is receiver-initiated, because the thief pulls. Pure pieces bind no local resources, which is why moving them is trivial. |
| 4 | failure models; recovery without checkpoints; logging | Assumed failures: process crashes and node loss (crash failures). Recovery keeps the input (the piece) at its owner until the result arrives. That is close in spirit to sender-based logging: re-execution replaces checkpoint and rollback, and purity makes it correct. |
| 5 | consistency; CAP; caching immutable data | No mutable shared state, so there are no replica-consistency problems for results. The one replicated state is membership: each node's member list is refreshed by gossip, so views are eventually consistent and stealing tolerates them being stale. Under a partition the owner re-solves locally: the job completes at the cost of duplicate work, and the value cannot be wrong because it is deterministic. |
| 6 | consensus; FLP; crashed vs slow | Thunk needs no consensus: each piece has exactly one owner. FLP's core difficulty, a crashed process looking like a slow one, is harmless here. A wrong suspicion only duplicates pure work. |
| 7 | ledgers as middleware | Not relevant to Thunk. Say so if asked, rather than forcing a connection. |
| 8 | architectural styles; process algebra | Decentralised peer-to-peer over message passing (BEAM processes); the dashboard is an observer that joins the cluster and polls, outside the computation. The steal protocol is small enough to model as a process term or a worker state machine in the report. |
| 9 | orchestration; reconciliation; self-healing | The Compose cluster could move to Kubernetes via Kompose (the tool used in the lecture). Kubernetes restarts a crashed node's container; Thunk's own mechanism recovers the work that was in flight. Two layers of self-healing, each with its own job. |
These are the points that show understanding best, because each one uses a course concept to explain a design choice.
The node that submitted the job holds the root of the tree, and if it dies the job is lost: a single point of failure per job. If an owner (not the root) dies, its own owner re-solves the whole enclosing piece, so the cost of a failure grows with the height of the lost subtree. Purity is an assumption about programs: side effects (I/O, randomness) would break arguments 1–3.
Crash failures of evaluator processes and whole nodes (Ch. 4). Detection comes from BEAM monitors: a DOWN message when a monitored process dies, or when the connection to its node is lost (heartbeat timeout). A partition therefore looks like node loss. Language errors are not faults to mask: they are deterministic, so they are re-raised.
Both computations produce the same value, so correctness is safe either way. Be ready to point to the code that shows what happens to the late reply (it is keyed by a reference, and the owner is no longer waiting for it). The cost is only duplicated work.
Each piece has a single owner, and pure results need no agreement: any correct evaluation is the result. You would need agreement if nodes had to decide on shared mutable state or on exactly-once side effects, e.g. a job queue that must never run a job twice, or dynamic membership with a consistent view.
Termination is detected structurally: every piece's owner waits for its halves, and the job ends when the root returns. Compare with Dijkstra–Scholten, where a diffusing computation keeps a tree of acknowledgements and the root knows the computation is over when all its children have acknowledged.
A node needs one reachable seed; it retries its seeds every second until it knows a member, then pulls a random peer's member list every 2–3 s and connects to the nodes it did not know. A node that goes down is dropped on nodedown. There is no agreement: views are eventually consistent (Ch. 5), and that is enough, because a stale view only makes a steal request fail. Agreement would be needed if a decision had to rest on one consistent view (Ch. 6).
Pieces (work described as data, with a job id) and, on demand, the job's definitions. It is weak mobility (code plus data, no execution state), receiver-initiated (the thief pulls), with no bindings to local resources. Avoiding serialised closures keeps pieces self-describing and independent of the sender's runtime (Ch. 3).
Nowhere for correctness. Physical time appears in failure detection (heartbeat timeouts) and in performance measurement. If you add a dashboard that merges logs from several nodes, order the log with Lamport timestamps plus node id, so that a result never appears before its piece (Ch. 2).
The split threshold (too fine means too much messaging), random stealing when little work is left, fetching definitions on first steal, and the fan-in at owners. Measure speedup as nodes are added, and show the curve in the report.
Re-execution could repeat effects, so recovery would need exactly-once delivery or output commit (Ch. 4), caches could go stale (a consistency model would be needed), and false suspicions would become dangerous. The difference shows how much work purity does.
A report that makes the concepts visible:
“Thunk replaces agreement with ownership and replaces rollback with re-execution. Both are correct because pieces are pure, so wrongly suspecting a slow node costs time, never correctness.”