CodeRigor

FREE LESSON

Producer-consumer state & backpressure

Model admission, worker ownership, completion and graceful draining without threads or timing assumptions.

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.

Ready, owned, completed
start / 3
Claim moves a job; completion releases its unresolved slot.
Ready, owned, completed
Claim moves a job; completion releases its unresolved slot.

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.

Python
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.

Two workers can finish in another order
start / 4
The unresolved count remains two through both claims and falls on completion.
Two workers can finish in another order
The unresolved count remains two through both claims and falls on completion.

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.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Watch 2:00–8:30 to name the producer/queue/consumer boundaries, then 20:30–33:50 for the consumer example. Use the authored pool for ownership and graceful-close rules.