One Task, One Owner: A Claim and Lease Model for Shared Work Queues
When two staff open the same queue, both can see the same task and both can press start. This article proposes a claim with a lease. It is a conditional design, not a statement about any particular tool.
State model
States: queued, claimed, started, done. Fields: owner, lease_until, version.
Transitions:
- queued to claimed: allowed only where state is queued. Sets owner and lease_until.
- claimed to started: allowed only for the same owner while the lease is current.
- claimed or started back to queued: only through lease expiry or an explicit release.
- started to done: owner only.
Each transition is a single conditional update that checks the expected state and version, and the number of rows changed tells you who won.
Claim rules
- Claim is an atomic conditional write, never read-then-write in two steps.
- The loser sees a clear message naming the current owner.
- Starting requires the lease to be valid at that moment.
- The owner may renew the lease before it ends, with the same version check.
- Choose the lease length from how long a typical step takes, and review it with real observation.
Branches
- Two claims at once: one succeeds, the other changes zero rows.
- Owner goes quiet and the lease passes: the task returns to queued; the old owner's later start fails the check.
- Side effects already begun by the first owner before expiry: do not assume nothing happened. Mark the task needs_check so the next person confirms before repeating any external action.
- Owner finishes after the lease lapsed but before anyone reclaims: allow completion only if state and owner still match.
Worked example
Task T1 is queued. Staff Amal and Bilal both click claim.
- Amal's write lands first: owner Amal, version 2.
- Bilal's write expects version 1, changes 0 rows, sees owned by Amal.
- Amal starts within the lease, version 3.
Task T2 is claimed by Amal, who steps away. The lease lapses and T2 returns to queued, needs_check. Bilal claims T2 at version 5, reviews the history and proceeds. If Amal returns and presses start, her write expects the old owner and version and is rejected.
Count: 2 tasks, 2 claim winners, 1 claim rejected, 1 lease expiry, 1 needs_check.
Stop conditions
Stop automatic requeueing if lease expiries spike beyond a threshold you set, or if the time source is unreliable, since leases depend on a trusted clock. A lease reduces duplicates but a local claim alone does not prove exclusive external effects.
Proposed acceptance tests (proposed, not performed)
- Two simultaneous claims: expect one owner.
- Start after lease expiry by the previous owner: expect rejection.
- Renewal by a non-owner: expect rejection.
- Expiry on a task with recorded side effects: expect needs_check and no automatic repeat.
- Repeat the expiry sweep: expect no further change.