Why it matters
thread-queue-timer is the pattern the new timers skill (#446) recommends for long-running work. As written, results get stranded and a failing job leaves a timer polling forever. Agents will copy it verbatim.
Evidence (code reading)
snippets/thread-queue-timer.py:29-48; the same pattern appears in skills/timers-modal-and-threading/SKILL.md:64-73.
- Stranded results: two
run_in_background() calls start two workers. Once the first result arrives, _drain returns None, which unregisters the timer, and the second result sits in the queue until something registers a timer again.
- Endless polling: if
job() raises, the worker thread dies without calling put(), and _drain re-runs every 0.1 s forever. Nothing reports the error.
Suggested approach
- Keep a pending-job counter, or one timer per job. Drain everything available in each tick, and unregister only when the pending count reaches 0.
- In the worker, wrap
job() in try/except BaseException as e and put((False, e)). The drain re-raises or reports the error on the main thread.
- Extend
examples/timers-modal-threading with a two-job case and a raising job, each with a falsifier.
Done when
The snippet and skill handle N concurrent jobs and job exceptions, and the example proves both on 5.2 and 4.5.
Why it matters
thread-queue-timeris the pattern the new timers skill (#446) recommends for long-running work. As written, results get stranded and a failing job leaves a timer polling forever. Agents will copy it verbatim.Evidence (code reading)
snippets/thread-queue-timer.py:29-48; the same pattern appears inskills/timers-modal-and-threading/SKILL.md:64-73.run_in_background()calls start two workers. Once the first result arrives,_drainreturnsNone, which unregisters the timer, and the second result sits in the queue until something registers a timer again.job()raises, the worker thread dies without callingput(), and_drainre-runs every 0.1 s forever. Nothing reports the error.Suggested approach
job()intry/except BaseException as eandput((False, e)). The drain re-raises or reports the error on the main thread.examples/timers-modal-threadingwith a two-job case and a raising job, each with a falsifier.Done when
The snippet and skill handle N concurrent jobs and job exceptions, and the example proves both on 5.2 and 4.5.