All notable changes to this project are documented here. The format follows Keep a Changelog and the project uses Semantic Versioning.
Unreleased
0.2.1 - 2026-10-22
First release published to Hex.
Changed
:retry_stormnow honours its window forretryablejobs too: aretryablejob counts only if its last failed attempt started within the window (attempted_at >= now - window, with a redundantscheduled_at >= now - windowbound so the query is an index range scan on Oban's(state, queue, priority, scheduled_at, id)index). Up to v0.2.0 everyretryablejob counted regardless of the window, so a worker with many jobs waiting out long backoffs from failures hours ago could fire a "retry storm in the last 300s". Expect fewer:retry_stormfindings after upgrading.:orphanedfindings and docs now say what is measured: execution age only. The message reads "executing for up to N s (limit L s), far beyond any expected runtime; possibly orphaned by a node crash or shutdown, or genuinely still running" instead of implying the node died. The check name is unchanged.
Documentation
- README: "Piloting safely" (report-only rollout, what to measure, tuning, retention for
history-based checks);
:stalledalso fires for queues whose slots are all held by long-running jobs. docs/OBAN_PRO_COMPATIBILITY.mdand an Oban Pro row under "Engine support": likely compatible, unverified and untested, with the Pro features known to skew results.docs/SECURITY_REVIEW.md: updated:retry_stormSQL listing.
0.2.0 - 2026-10-22
First public release, tagged on GitHub. (An earlier version of this entry said it was
published to Hex; it has not been published to Hex yet.) 0.1.0 (below) was an
internal milestone: it was never tagged, released or published, and it had the
production-safety problems listed under "Fixed" (see the findings QK-01 to QK-11 in
docs/SECURITY_REVIEW.md). If you pinned a pre-release commit from GitHub, read
"Changed" before upgrading.
Fixed
mix queue_keeper.checkno longer starts the host application (and therefore Oban, its queues and plugins); it loads config and starts only the repo (QK-01).- Queries that could take minutes on large tables: sample queries no longer
ORDER BY id;:orphaned/:hangingaggregate in SQL;:stalledprobes only late queues with index-boundedLIMIT 1queries; sample queries capped at 100 per run (QK-02, QK-07). - Text output replaces control/bidi characters; Slack payloads escape
&,<and>(QK-05). sample_idsno longer render as a charlist (QK-08).
Added
QueueKeeperCheck.Guard: on Postgres every check runs in a rolled-back transaction withtransaction_read_only,statement_timeout,lock_timeoutandidle_in_transaction_session_timeout; on MySQLmax_execution_time(QK-03).- Options
:statement_timeout(5000),:lock_timeout(1000),:check_timeout(30000),:read_only(true);stalled: [lookback: 3600];retry_storm: [include_completed: false]. report.errors, status:errorand exit code 3; per-check error isolation; remaining checks are skipped after a connection error (QK-04).- Strict option validation, including an identifier allow-list for
:prefix(QK-06). SECURITY.md,docs/SECURITY_REVIEW.md, benchmark and verification scripts.- CI on PostgreSQL 17, SQLite and MySQL 8.4, with actions pinned to commit SHAs and
mix hex.audit(QK-09).
Changed
:retry_stormcounts completed retried jobs only withinclude_completed: true(that part needs a full table scan).Release.check/2never raises, starts the repo with a pool of 1 and stops it afterwards.- Running
QueueKeeperCheck.run/2inside an open transaction on Postgres is refused. - Errors (bad options, database unreachable, timeouts) now exit with 3 instead of 1, so "could not check" is no longer reported as "warning" (QK-04).
- Unknown or invalid options raise
ArgumentErrorinstead of being ignored (QK-06).
Known limitations
:cron_missing(opt-in) needs a sequential scan; it is bounded by:statement_timeout(QK-10).- On MySQL and SQLite, read-only enforcement depends on a SELECT-only database user or a
read-only connection; the library only issues
SELECTs (QK-11).
0.1.0 - 2026-10-22 (never published)
Initial implementation. Not tagged, released or published; superseded by 0.2.0.
Added
QueueKeeperCheck.run/2: read-only checks onoban_jobsfor:orphaned,:hanging,:backlog,:stalled,:retry_storm,:discarded,:cancelledand:cron_missing, with configurable thresholds (QueueKeeperCheck.Config).QueueKeeperCheck.format/1(plain text) andQueueKeeperCheck.slack_payload/1(Slack incoming-webhook body; never sent by the library).mix queue_keeper.checktask with exit codes 0 (ok), 1 (warning), 2 (critical).QueueKeeperCheck.Release.main/2/check/2for running from a release viaeval, outside Oban (e.g. system cron).- Support for Oban's Basic (PostgreSQL), Lite (SQLite3) and Dolphin (MySQL 8.4+) engines.