Skip to content

Changelog

Version v0.14.0

What’s Changed

Features

  • Caller-supplied job IDs (breaking): startChain, startChains, and the worker continueWith callback now accept an optional id that becomes the new chain root (or continuation) job ID. State adapters accept a new validateId predicate that runs on both adapter-generated and caller-supplied IDs; failures throw the new InvalidJobIdError. When deduplication fires, the existing row’s ID wins over a caller-supplied id (the returned chain carries deduplicated: true).
  • Aligned adapter ID-generation options (breaking): both PostgreSQL and SQLite adapters now expose a generateId function. PostgreSQL’s idDefault (SQL expression) is removed in favor of JS-side generation; SQLite’s idGenerator is renamed to generateId. A new PostgreSQL migration drops DEFAULT gen_random_uuid() from the id column. Existing UUID generation behavior is unchanged for default configurations.

Bug Fixes

  • scheduled_at is now an honest eligibility floor: state adapters clamp scheduled_at to MAX(requested, now()) on createJobs, rescheduleJob, and unblockJobs. Previously, jobs with a past scheduled_at (or blocked-since-creation jobs whose original scheduled_at went stale while they waited) would jump to the front of the acquisition queue ahead of jobs that genuinely became ready earlier. unblockJobs now preserves a future scheduled_at set at job creation (it previously reset to now() unconditionally); triggerJobs continues to re-anchor to now() as an explicit reset. Applies to PostgreSQL, SQLite, and in-process adapters; no schema migration or backfill required.
  • lastAttemptError cleared on success: when a job completes successfully after a previously failed attempt, completeJob now resets last_attempt_error to NULL alongside the existing status/output/lease updates. Completed rows no longer carry over an error string from a prior failed attempt.
  • requiredAttemptMiddleware type fix: a spurious type error from createInProcessWorker’s requiredAttemptMiddleware check is fixed when middleware is typed against a user-supplied StateAdapter alias (e.g. AttemptMiddleware<MyStateAdapter>). Valid processor slices were being flagged as missing required middleware. Runtime behavior was unaffected; this is a type-only fix.
  • BaseTxContext tightened: changed from {} to Record<string, unknown>. The previous {} constraint accepted any non-nullish value (string, number, function), letting custom StateAdapter authors pick a non-object TTxContext without a type error. All built-in adapters are already object-shaped, so no runtime behavior changes.

Migration Notes

  • PostgreSQL: replace idDefault: "gen_random_uuid()" with generateId: () => crypto.randomUUID() (this is the default and can be omitted).
  • PostgreSQL: replace idDefault: "'job.' || gen_random_uuid()::text" with generateId: () => `job.${crypto.randomUUID()}` .
  • SQLite: rename idGenerator option to generateId.
  • Custom state adapter implementations must accept an optional id per entry in createJobs and apply their own validateId predicate.

Packages

All packages released at 0.14.0: queuert, @queuert/postgres, @queuert/sqlite, @queuert/redis, @queuert/nats, @queuert/otel, @queuert/dashboard.