Phase 1 of the roadmap to v1.0.0: three concurrency bug fixes.
Behavior changes
run_task_immediately()now raisesTaskNotActiveErrorwhen the task is notactive. Previously arunningtask could be dispatched a second time concurrently (breaking the no-overlap guarantee) and apausedtask was silently un-paused. Resume paused tasks explicitly withresume_task().
What's new
shutdown(timeout=...)/stop(timeout=...)— optional bound on how long shutdown waits for the scheduler thread and in-flight jobs. Jobs that do not exit within the deadline are abandoned on their worker threads with a warning, so a hung handler can no longer block application shutdown forever. Default (timeout=None) keeps the previous wait-forever behavior.- New exception
TaskNotActiveError(exported fromquiv).
Fixes
remove_task()racing the dispatch loop could raise aKeyErrorthat stalled the scheduler for 5 seconds; dispatch now skips removed tasks gracefully, and the shared handler/callback/stop-event registries are protected by a lock.shutdown()now signals cancellation only torunningjobs instead of scanning the entire retained job history.
Housekeeping
- Roadmap phases renumbered: v0.3.x/v0.4.x were already consumed by earlier feature releases, so Phase 1 ships as
v0.5.0and later phases shift down accordingly (Phase 6 staysv1.0.0). - 7 new regression tests; docs, release notes, and AI-tooling artifacts updated; version bumped to
0.5.0. - Docs cleanup: all Markdown files unwrapped to one paragraph per continuous line (zensical can break rendering when a sentence/paragraph is split across source lines). No content changes.