Skip to content
← Free FDE training guides

Free learning / 50-minute worker and destination proof lab

Worker fencing: a lost lease does not undo the effect

Pause an actual worker before a separate destination effect. Compare queue completion guards, committed destination fences and operation receipts across seven controlled two-process SQLite cases.

No account needed. Use your own copy for writing and keep the original as a reference.

Engineering lab library / Run locally

Run the destination boundary.

Predict the seven cases, then compare actual destination effects with the separate queue completion. Change only the units and give another engineer the receiving task.

Two real local processes and two scratch SQLite databases. Logical ticks are injected. No network, real tool action or production authentication; run the standalone file in your terminal.

  1. Start here / Python 3.11+ · Standard library

    Worker leases, destination fencing and operation receipts

    Expose late effects, same-token repeats, payload conflicts and a rolled-back fence proposal at the actual destination.

    Python 3.11+ · Standard library · Two owned processes and scratch SQLite files · No network

Original LockedIn Labs proof workshop · 50 planned minutes, excluding setup · Python 3.11+ standard library. Two owned local processes use two temporary SQLite files. The runner makes actual database changes and pauses an actual worker; the clock is injected logical time. There is no network, broker, model, real tool action or production authentication.

1. Separate ownership from the work already done

A lease gives a worker a bounded ownership interval under an authority's rules. Expiry lets another worker take over; it does not necessarily stop the old process. A paused worker can resume, or an earlier request can arrive late.

A fencing token identifies an ownership generation. In this exercise, the queue issues increasing integers. The destination keeps the highest token committed by an admitted, non-conflicting transaction for its one synthetic resource and rejects smaller tokens. A received token or an uncommitted update does not establish that stored boundary. The token is not an access credential, a timestamp, a business operation ID or proof that the sender is currently authorized.

An operation receipt answers another question: did this destination already apply this particular business operation with this payload? Equal fencing tokens are allowed, so fencing alone does not suppress a same-owner retry. Stable operation identity, payload agreement and an atomic receipt/effect boundary are separate controls.

The existing worker-recovery lab protects completion inside its queue database. This workshop tests the next boundary: what happens if the worker changes a separate destination before discovering that it lost the queue lease?

2. Follow two databases through one pause

Worker A claims JOB-1 at logical tick 0, with fence 1 and expiry 5. It reads the job successfully and pauses before calling the destination. After receiving that real pause event, the parent process also acts as worker B: it claims the same job at tick 5 and receives fence 2. This is two real processes with separate connections, not a distributed lease service.

Both workers represent the same intended OP-1, adding four units to one fictional counter. The queue and destination are separate SQLite files. No transaction spans both. When A eventually calls finish at tick 6, the queue refuses it with lease_lost. Inspect the destination anyway: its earlier committed effect may remain.

The resource gate compares supplied_fence < committed_high_water inside its writer transaction. It advances the high-water mark only for admitted, non-conflicting work, including a matching receipt replay. Its stored mark survives closing and reopening that scratch file. It does not ask the queue whether the lease is current.

This distinction follows the destination-side sequencer problem described in section 2.4 of the original Chubby paper. Our integers, clock, schema and counter are an original teaching fixture, not a Chubby implementation.

UNDERSTAND THE SYSTEM

A lost lease does not undo a destination effect

Six authored frames explain the boundary exercised by two real local processes and two scratch databases. Logical ticks are injected. Trusted fixture counters are not authenticated production tokens, and the destination's committed fence is not a live lease check.

FOLLOW THE WORK

Watch one example, step by step.

6 authored stepsYou control the pace
01 / EXPLORE THE PARTSControls loading · written explanations below
Direction of information or workReturn / feedback

WHAT THIS PART DOES

Paused worker A

A checks fence 1, then pauses before calling the separate destination. It can resume after losing the queue lease.

CONNECTED TO
  • Claim and precheck: Queue lease authority
  • Late fence 1: Destination fence
Read the full worked example
  1. 01
    Check, then pause

    A's successful early precheck says nothing about authority when a later effect commits.

    Actual runner boundary: A owns fence 1 before pause

  2. 02
    Reclaim elsewhere

    The queue now records B at fence 2, but the separate destination has not observed that token yet.

    Separate stored facts: Queue fence 2 · destination highest 0

  3. 03
    New reaches destination first

    With fencing enabled, B applies four units and establishes highest 2. Late fence 1 is then refused.

    fence-new-first: Four units · old request fenced

  4. 04
    A newer attempt rolls back

    B's failing connection temporarily reads mark 2 and four units. The actual rollback leaves committed mark 0 and zero units. A can then apply fence 1; the queue still belongs to B.

    fence-rollback: Own connection: 2 / 4 · committed after rollback: 0 / 0

  5. 05
    Old reaches destination first

    After reclaim, A can still pass a committed-mark check at zero. B then applies too. Equal-token repeats also need their own control.

    fence-old-first / same-fence-repeat: Eight units · queue still finishes once

  6. 06
    Bind one business operation

    The combined candidate retains one receipt and four units even when A reaches the destination first. It prevents a duplicate local effect, not an earlier stale attempt or a wrong payload.

    fence-and-receipt: Four units · one receipt · new token replays

Read the connections in plain English
  1. 01
    Paused worker A → Queue lease authority

    A acquires fence 1 before its controlled pause.

  2. 02
    Queue lease authority → Current worker B

    A's lease expires in the injected queue clock; B receives fence 2.

  3. 03
    Current worker B → Destination fence

    The destination establishes the newer fence when an admitted transaction commits it.

  4. 04
    Paused worker A → Destination fence

    A still reaches the destination before its queue completion is refused.

  5. 05
    Destination fence → Operation receipt

    A fence orders epochs; the optional receipt deals with repeated application of OP-1.

  6. 06
    Operation receipt → Destination effect

    The receipt and four-unit local effect share one destination transaction.

Check your understanding: Does granting fence 2 make every later fence-1 call fail immediately?

No. This destination compares with its committed admission mark, not the queue's current lease. It refuses 1 after an admitted transaction commits 2; a rolled-back attempt does not establish that mark. A stable operation receipt is a separate requirement for repeated business work; production authority and authenticated token issuance still need their own contract.

3. Predict and run six controlled receiving cases

Download the standalone Python runner into a disposable folder and read it first:

Code example
python3 --version
python3 fde-worker-fencing.py > fencing-original.json
python3 fde-worker-fencing.py --case fence-old-first
python3 fde-worker-fencing.py --case fence-and-receipt --units 3 > fencing-three.json

On Windows, use py -3 if that is your Python launcher. There are no package installations or outside requests. Each case owns and cleans up its child process and temporary databases. Do not reuse an output filename if you want to retain the earlier report. The runner accepts only a named case and units from 1 through 9; it accepts no secret, service URL or arbitrary database path.

Predict the six baseline outcomes before inspecting the report. The seventh rollback comparison is explained in the next section:

CaseDestination contract and delivery orderActual final units / receipts
finish-onlyNo destination fencing; B applies, then paused A applies8 / 0; A's queue completion is still refused
fence-new-firstB establishes highest 2 before A arrives4 / 0; A is fenced at the destination
fence-old-firstA arrives after queue reclaim but before destination sees 28 / 0; both destination calls apply
same-fence-repeatB repeats fence 2; A later arrives8 / 0; equal tokens do not deduplicate
fence-and-receiptA arrives first; B and its repeat use the same operation/units4 / 1; B replays and advances highest to 2
changed-operationB applies, then retries OP-1 with changed units4 / 1; the changed payload conflicts

All seven default queue histories finish with worker B, fence 2 and two claims. That identical queue state hides very different destination effects. attempts retains the actual before/after resource state and destination result in the controlled arrival order. The old worker's process ID differs from the coordinator/new worker's process ID; old_worker_exit records a normal exit. This is a pause/resume exercise, not a worker-kill or network-partition experiment.

The second command isolates the subtle case: A's effect can be admitted at destination highest 0 even though the queue already assigned fence 2. The third changes the operation from four to three units; it should retain three units and one receipt, not an invented four-unit reference.

3a. Observe the fence rollback boundary

The default report now includes a seventh comparison, fence-rollback. Run it separately before assuming that receiving a newer token establishes a durable fence:

Code example
python3 fde-worker-fencing.py --case fence-rollback > fencing-rollback.json
python3 fde-worker-fencing.py --case fence-rollback --units 3 > fencing-rollback-three.json

B holds the current queue lease at fence 2. Its destination transaction updates the high-water mark to 2 and increments the counter, then a deliberate exception occurs before the receipt insert and commit. uncommitted_failure_view records only that failing connection's own view. It is not a committed snapshot available to worker A. The transaction rolls back before A is released.

Actual attemptFailing connection's temporary viewCommitted destination after the attempt
B / fence 2 / controlled failurehighest 2, four units, no receipthighest 0, zero units, no receipt
A / fence 1 / released after rollbacknot applicablehighest 1, four units, one receipt
B / fence 2 / matching retrynot applicablehighest 2, four units, one receipt; replayed

The first attempt’s queue_after_destination records B still running at fence 2 after the destination rollback. A's destination call is admitted against committed mark 0 even though the destination previously attempted to process 2. A's queue completion is refused. B's later matching replay commits mark 2 without another increment. With --units 3, the temporary and retained effect values are three instead of four; the zero-after-rollback observation remains zero.

The fixture’s highest_fence is therefore a committed admission mark, not a log of every token received. This is the contract implemented by this atomic destination transaction, not a universal fencing-service specification. A design that persists an epoch independently from the business action has another recovery boundary and needs separate tests. This controlled exception is not an OS crash, power loss or unavailable database.

4. Keep fencing, freshness and idempotency distinct

This destination’s committed fence protects an ordering boundary: after an admitted transaction establishes 2, a request carrying 1 cannot apply there. A failed or conflicting transaction rolls its tentative high-water update back with its effect. It does not establish immediate revocation when the issuer grants 2, and it does not prove wall-clock expiry. A separate current-authority contract may be needed; an early worker-side check followed by a remote effect leaves a gap.

A same-fence repeat remains admissible. In same-fence-repeat, both B calls add four units. In the combined candidate, the destination instead binds OP-1 to the requested units. A matching retry returns the stored result without another increment. A different units value conflicts and rolls back the transaction. The high-water mark, receipt and effect live in one local transaction; they do not share a transaction with the queue.

The combined old-first case is deliberately limited: A still performs the first local effect while its queue lease is stale. The matching operation receipt prevents a second effect. It does not retroactively authorize A, choose a correct changed payload, authenticate either worker or undo an already committed action. Real permissions, operation meaning and recovery remain distinct.

The runner uses explicit BEGIN IMMEDIATE, followed by commit or rollback, on connections with isolation_level=None. Read the primary SQLite transaction contract and Python transaction-control reference before adapting the pattern. SQLite serializes its writers; a local counter result is not evidence of remote exactly-once execution.

5. Hand the proof to another engineer

Spend the final ten minutes on a receiving task. One person retains the original report; another predicts --case fence-old-first --units 3, runs it themselves and locates the two actual effects totaling six. Swap roles for fence-and-receipt --units 3: the receiver must locate one three-unit effect, one receipt and highest fence 2. Keep each person's prediction, command, observed evidence, assistance and correction separate. Solo practice is self-review.

For the rollback case, have a receiver locate the failing connection’s temporary mark, the zero committed mark after rollback and the unchanged queue lease before explaining A’s admission. Keep those three observations distinct.

The application owner names the stable operation, payload agreement and reconciliation rule. The queue/platform owner explains token issuance, scope, persistence, clock and recovery after failover or restore. The destination owner must show where the token is checked and where the receipt/effect commits. The pod lead records which boundary remains untested and who receives the next bounded task. A shared presentation or a green process exit does not establish an individual's independence or qualification.

Before a real adaptation, agree the token's issuer and resource scope, authenticated transport, monotonicity across recovery, current-authority expectations, receipt retention, payload conflicts, concurrent requests and uncertain destination outcomes. Do not assume two independent locks' token numbers are comparable or that a token alone authorizes access. This fixture supplies trusted inputs for one job and one resource; it implements none of that production infrastructure.

6. Defend the decision in an interview

  • Why did A's refused completion fail to protect the destination? The destination committed first in another database. A queue update cannot undo that effect.
  • Why did the old-first fenced case still apply twice? The destination had not yet observed the newer token, and fencing did not deduplicate OP-1.
  • Why does receiving token 2 not always establish the stored fence? In this fixture the mark commits with the destination transaction. A rollback preserves the earlier committed mark, even when the failed connection briefly saw 2.
  • Why is the combined case still not a complete authority guarantee? A performed the first effect after losing its queue lease. A receipt limits repetition; it does not prove current permission or a correct business payload.

Keep a short record: original prediction, exact runtime/file/command, each destination state, the separate queue outcome, one changed-input comparison, help received and the next accountable owner. Continue with uncertain action recovery to investigate destination receipts when the caller does not know whether an effect committed.

Before you move on

Keep the evidence of your work.

  • Individual predictions beside actual worker, queue and destination observations.
  • Original and changed-unit reports separating current ownership from already applied effects.
  • A receiving action naming application, platform, destination and pod responsibilities.

Keep these in your own working copy. Reading this page does not save work or record completion.

Suggested next free session

Recover an agent action when the receipt is missing

Reconcile a destination receipt when the caller does not know whether its effect committed. This is a suggested sequence; choose the practice that addresses your current gap.

Open the next free guide

Free account

Give your practice a home.

Try a role exercise with account drafts and a downloadable worksheet. Keep the files you made in this guide in your own working copy.

Create a free learning account

Guided training · by application

Build toward a program.

Request structured lessons and a training seat. Scope, schedule, feedback arrangements and tuition are confirmed in writing before you commit.

Explore a training application
Have Academy access?

Use your existing training seat to open worked explanations and practice in the related lesson. Creating a free account does not grant a seat.

Open the related Academy lesson →
Back to top ↑