Skip to content
Get started
Get started
bunqueue v2.8.17
View Markdown
blog · release

bunqueue v2.8.17

Fixes 1 bug. Retrying a job that reached failed through the lock-expiry path failed with UNIQUE constraint failed: jobs.id (src/application/lockManager.ts): handleMaxStallsExceeded moved the job to the DLQ using only in-memory state…

bun add bunqueue@2.8.17
npm install bunqueue@2.8.17
bun add bunqueue@latest
  • Retrying a job that reached failed through the lock-expiry path failed with UNIQUE constraint failed: jobs.id (src/application/lockManager.ts): handleMaxStallsExceeded moved the job to the DLQ using only in-memory state (shard.addToDlq + jobIndex.set). Unlike its three sibling paths, ack.moveFailedJobToDlq (max attempts), stallDetection.moveStalliedJobToDlq (heartbeat stall), and the startup recovery in backgroundTasks, it never called storage.saveDlqEntry(entry) nor storage.deleteJob(jobId). So the jobs row survived in SQLite as an orphan (state active) and the DLQ entry lived only in memory. On retry, dlqManager.retryDlqJob re-INSERTs the job with its original id via the plain INSERT INTO jobs statement (not INSERT OR REPLACE like insertResult/insertCron), and the surviving orphan row raised the UNIQUE violation, failing the retry; a restart in that window also re-recovered the stale active row. The lock-expiry DLQ move now persists like its siblings (capture the DlqEntry, then saveDlqEntry + deleteJob), restoring the single-table-residency invariant. deleteJob also evicts the id from the write buffer, so a non-durable job cannot later flush a stale INSERT and re-orphan.

← bunqueue v2.8.16 · Release on GitHub · Commits since v2.8.16 · Full changelog · All posts