Repository navigation
What's Changed
Queuert 0.16 rebuilds the job model around the chain's head row and reworks attempt handling around a single finish outcome API, with a one-step schema migration from v0.15.1. It also brings faster listing queries, a redesigned dashboard, and a leaner, more consistent public API. This release contains many breaking changes — review the notes below before upgrading.
Breaking Changes
- New job model — a chain's head row is now the chain itself.
ChainStatusis justrunning|completed; completed jobs carrycontinuedToId; running jobs exposeattemptAt/attemptBy/attemptUntil. "Lease" is renamed to "attempt" throughout (leaseConfig→attemptConfigwithtimeoutMs/heartbeatMs,LeaseConfig→AttemptConfig, plus matching log events and metrics). - Attempt finalization — handlers end an attempt with
complete(async ({ finish }) => finish({ output | continueWith | reschedule })).rescheduleJob()andRescheduleJobErrorare removed; rescheduling is now a non-error outcome.completeChain'scompleteoption is renamed tohandler. - Renames —
startChain/startChains→createChain/createChains. - Listing API reshaped — flat options with a single
status, requiredtypeName, status-dependentorderBychecked at compile time,root→independent; thechainId/jobId/chainTypeNamefilters are removed;CreatedAtCursor→TimestampWithIdCursor. - Deduplication —
scopeis now required and"incomplete"is renamed to"running"(missing or unknown scopes throwTypeError).windowMsandexcludeChainIdsare removed. - Caller-supplied
idcollisions now throw instead of being silently ignored. cascaderemoved fromdeleteChain/deleteChains.TransactionContextRequiredErrorremoved — a plainErroris thrown instead.wrapHandlernow wraps the whole attempt, so acatcharoundnext()observes handler failures.- Public type exports pruned — internal helper types are no longer exported;
CompletedJobandAttemptConfigare newly exported.
Database Migrations (@queuert/postgres, @queuert/sqlite)
- All migrations are collapsed into
001_initial_schema. You must be on v0.15.1 before upgrading. - PostgreSQL: the upgrade copies tables while v0.15.1 workers keep running; a
migration_locktable makes concurrentmigrateToLatest()calls safe. - SQLite: stop all workers and clients before running the migration.
vacuum()is removed, along with SQLite'scheckForeignKeys/checkAutoVacuumoptions.
Features
steptransaction primitive inside attempt handlers, with a matchingwrapStepmiddleware hook.- Batched lookups —
getChains/getJobs, withChainTypeMismatchError. - Type names & counts —
listChainTypeNames/listJobTypeNamesandcountByChainTypeNames/countByJobTypeNames. - Worker shutdown signal — in-flight handlers receive
"worker_stopping"as the abort reason when the worker stops.
Dashboard
- Full UI redesign: Overview page, Find by ID (⌘K), status tabs, and themes.
- New endpoints for type names, counts, and by-ID lookups. Malformed IDs and unknown
/apipaths return 404; uncaught errors return 500 with an{ error }body.
Observability (@queuert/otel)
- Attempt spans record an
abortevent;prepare/step/completespans record exceptions andERRORstatus. - Breaking: blocker-completion span renamed
resolve chain.*→complete chain.*;queuert.attempt.resultattribute removed (read the outcome from span status); metric names follow the lease → attempt rename. @opentelemetry/apipeer dependency now also accepts^1.0.0.
Performance & Fixes
- Faster listing queries via per-type anchoring.
- PostgreSQL and SQLite skip the redundant
RELEASE SAVEPOINTround-trip. - Type checking is roughly 20–40% cheaper.
AttemptMiddlewaretyped against a concrete adapter now works.chain.inputnow correctly reflects the entry job's input.- Fixed a race where a job created with blockers could start
pendinginstead ofblocked(#4).
Packages
All packages released at 0.16.0: queuert, @queuert/postgres, @queuert/sqlite, @queuert/redis, @queuert/nats, @queuert/otel, @queuert/dashboard.