Summary
There is an atomicity gap between waitForSettlement() closing its wait and settle() committing a fulfilled result.
For a stateful assignment, the close script currently:
- Reads the settlement key.
- Returns
nil when the workspace in-flight marker still points to the assignment.
- Leaves the assignment available for settlement.
A concurrent settle() can therefore commit immediately after the close script returns nil. Dispatch then throws ASSIGNMENT_EXPIRED, skips commitPendingWorkspace(), and enters failure cleanup even though the worker observed an accepted settlement.
The same interleaving is possible when the abort signal ends the wait before the absolute deadline.
Impact
The caller receives a deadline failure after work was accepted, and a stateful workspace can remain fenced because its pending marker was not committed. A retry may duplicate externally visible work or require a manual workspace reset.
Suggested direction
Make closing and settlement mutually exclusive in Redis. For example, atomically record a terminal closed/fenced state that the settlement script checks, or make the final settlement read/close operation choose exactly one winner while preserving the workspace marker on ambiguous outcomes.
Add a deterministic concurrency test that pauses settlement across the final close boundary and verifies one of these outcomes only:
- settlement wins and dispatch returns/commits it; or
- close wins and
settle() is rejected without storing a result.
Verified on current main (0eb0f3a30e984f23fa98d0cc48acc8abd21cb184).
Summary
There is an atomicity gap between
waitForSettlement()closing its wait andsettle()committing a fulfilled result.For a stateful assignment, the close script currently:
nilwhen the workspace in-flight marker still points to the assignment.A concurrent
settle()can therefore commit immediately after the close script returnsnil. Dispatch then throwsASSIGNMENT_EXPIRED, skipscommitPendingWorkspace(), and enters failure cleanup even though the worker observed an accepted settlement.The same interleaving is possible when the abort signal ends the wait before the absolute deadline.
Impact
The caller receives a deadline failure after work was accepted, and a stateful workspace can remain fenced because its pending marker was not committed. A retry may duplicate externally visible work or require a manual workspace reset.
Suggested direction
Make closing and settlement mutually exclusive in Redis. For example, atomically record a terminal closed/fenced state that the settlement script checks, or make the final settlement read/close operation choose exactly one winner while preserving the workspace marker on ambiguous outcomes.
Add a deterministic concurrency test that pauses settlement across the final close boundary and verifies one of these outcomes only:
settle()is rejected without storing a result.Verified on current
main(0eb0f3a30e984f23fa98d0cc48acc8abd21cb184).