Engineering note · 4 of 6
Generation fencing stops a late runner from winning. The poison pill
stops a cursed job from reclaiming forever — after
reclaim.max_retries, the run is terminal error, the thread is
released, and hooks fire. No infinite re-enqueue.
Not content filtering. A job that keeps killing runners (OOM, bad tool, broken graph) would otherwise bounce reclaim → dequeue → crash → reclaim… forever, burning capacity and drowning operators in noise.
attempt 1 dequeue · crash · reclaim generation++ attempt 2 dequeue · crash · reclaim generation++ attempt 3 dequeue · crash · next reclaim would be 4th ceiling (default 3): mark error · release thread · terminal event · do not re-enqueue
reclaim.max_retries in agent config (default 3).
0 → unlimited (legacy escape).RUNKITE_RECLAIM_MAX_RETRIES.Applies on Redis, NATS, and Kafka — same ceiling, no transport-only asymmetry. Distinct from live cancel and from Admin kill switches.
Fencing answers: “which attempt is allowed to write?” The poison pill answers: “how many attempts are allowed at all?” You need both — otherwise a well-fenced crash loop still never dies.
Operators get a hard stop they can explain: “it failed after N reclaims,” not “the queue is haunted.”