A producer submits work; a consumer claims work; completion records an outcome. These are three distinct events. Removing a job from the ready queue does not mean its processing has finished. A useful state model separates waiting work from work owned by a particular worker, then records completed jobs independently.
Our pool has a fixed set of worker IDs. Each worker may own at most one job. A busy worker's second claim returns None, even if the queue contains more work. Another idle worker can still claim the oldest ready job. This is an explicit deterministic sequence of method calls, so the lesson does not need operating-system scheduling or sleeps to demonstrate ownership.
The capacity in this build counts ready plus busy jobs. Many real queues instead bound only waiting entries, and broker prefetch may impose another independent bound on deliveries. Name the set that your number limits. Here, capacity two means two unresolved jobs in total: claiming one changes its location without permitting another admission. Only completion frees an unresolved slot.
from collections import deque
ready = deque(["a", "b"])
busy = {}
done = []
busy[0] = ready.popleft()
print(len(ready) + len(busy))
done.append(busy.pop(0))
print(len(ready) + len(busy), done)Backpressure is information sent toward the producer. submit returns False when no room remains; the caller must act on that result. Throwing the job away while returning success would conceal loss. A retry loop that ignores consumer progress could also keep the program busy forever. This local model reports the decision without inventing an upstream retry policy.
FIFO claim order does not imply completion order. Worker zero may claim a, worker one claim b, and b finish first. Preserve the actual completion history rather than sorting it to resemble admission. If an application requires ordered effects, it needs an additional policy, such as serializing jobs by account; the capstone will introduce that constraint.
A graceful close changes future admission, then allows admitted jobs to drain. It does not erase ready entries or revoke worker ownership. Calling close twice is harmless. Completing an idle worker is a programming error and raises ValueError; a valid idle claim returning None is an expected lack of work. Validate worker IDs before reading or changing state, so a negative ID does not silently address an unrelated worker.
In the bug hunts, watch for counts that drop merely because work was claimed and ownership records left behind after completion. In the build, verify busy-worker reclaims, closure with queued work, completion order and copied state views. These tests establish the state machine's contract. They do not run worker callbacks, synchronize threads, detect actual process death or guarantee delivery across a service boundary.