Day 46: Time (Lamport/vector clocks) & delivery semantics
Ordering events without a shared clock
Since wall clocks can't reliably order events across machines (Day 42), distributed systems use logical clocks instead. A Lamport clock is a simple counter each node increments on every event, and includes with every message it sends; a receiver sets its own counter to max(its counter, received counter) + 1. This gives a consistent 'happened-before' ordering — not real time, but enough to detect causality.
A vector clock goes further: each node tracks a whole vector of counters (one per node), letting you detect not just *some* ordering but whether two events are truly causally related or genuinely concurrent (neither happened before the other) — the extra information Lamport clocks alone can't provide.
Delivery semantics
- At-most-once — a message is delivered zero or one times; simple, but messages can be silently lost
- At-least-once — a message is retried until acknowledged, so it may be delivered more than once
- Exactly-once — delivered exactly one time, no loss, no duplication
Why exactly-once is mostly a lie
True exactly-once delivery would require perfect knowledge of whether a message was received AND processed AND acknowledged, across an unreliable network with partial failures — exactly the problem Day 42 said is unsolvable in general. What most systems that advertise 'exactly-once' actually provide is at-least-once delivery plus idempotency — processing the same message twice has the same effect as processing it once, so duplicates become harmless rather than actually prevented.
Non-idempotent: "increment balance by $10" — running it twice = +$20 (wrong if retried)
Idempotent: "set balance to $110" — running it twice = $110 either way (safe)
Idempotent via key: "charge $10, idempotency-key=abc123" — server deduplicates on the keyThe Four Questions: idempotent consumers (or Raft)
Worked example for Docker: dependency hell → consistent runtime environments → VMs too heavy → shared kernel, weaker isolation. Now apply it to idempotency: what problem (duplicate message processing from at-least-once retries) did it solve, why couldn't 'just don't retry' solve it, and what trade-off (extra bookkeeping — dedup keys/state) does it introduce?
Key terms
- Lamport clock
- A logical counter giving a consistent happened-before ordering of events across nodes without a shared clock.
- Vector clock
- A per-node vector of counters that can detect true concurrency, not just an ordering.
- Idempotency
- A property where repeating an operation has the same effect as doing it once — the practical antidote to at-least-once duplicates.
Phase 7 complete — you should now be able to
A payment API lets clients retry a POST /charge request safely using an Idempotency-Key header. What problem does this solve?