Skip to content

Call task_done() when a coordinator lane exits on a collected coordinator #97

Description

@bagowix

Problem

_sync_lane_tick / _async_lane_tick (interlock/_coordination.py:283-300, 441-464) pull an op off the work queue before resolving the weak reference:

op = work.get(timeout=interval)   # unfinished_tasks += 0? no: get() does not decrement
coordinator = ref()
if coordinator is None:
    return False                  # op dequeued, task_done() never called

If the coordinator was collected between the enqueue and the dequeue, the lane exits without work.task_done(), so queue.unfinished_tasks stays positive forever and wait_idle() (Queue.join()) on that queue can never return.

Severity

Low. In practice the only holder of wait_idle() is the coordinator itself, so once it is collected nobody can join the queue — the hang is currently unreachable outside a test that keeps a direct reference to _work (as test__async_lane_tick__runs_queued_op_and_dead_ref_stops does). It is still a broken queue invariant that becomes reachable the moment the queue is exposed (see the shutdown API issue).

Fix

Release the dequeued op before returning:

coordinator = ref()
if coordinator is None:
    if op is not None:
        work.task_done()
    return False

Acceptance criteria

  • Both lanes call task_done() on the drop path.
  • A test asserts work.join() returns after the lane exits with an op in flight and a dead coordinator ref.
  • Coverage stays at 100%.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions