- Docs
- Queue
- Control & Maintenance
Pause it, drain it, wipe it.
The operational verbs. Stop consumption during an incident, clear a backlog, remove finished jobs before they accumulate, and push delayed work forward when you cannot wait.
Control the queue
Section titled “Control the queue”queue.pause(); // Workers stop pulling (fire-and-forget)queue.resume(); // Back to normal (fire-and-forget)queue.drain(); // Remove all waiting/delayed jobs (fire-and-forget)queue.obliterate(); // Remove ALL queue data (fire-and-forget)
await queue.pauseAsync(); // Pause and wait for itawait queue.resumeAsync(); // Resume and wait for itconst n = await queue.drainAsync(); // Drain, wait, get removed countawait queue.obliterateAsync(); // Remove ALL queue data and wait for it
queue.remove('job-id'); // Remove one job (fire-and-forget)await queue.removeAsync('job-id'); // Remove one job (pending or completed) and wait for it
await queue.waitUntilReady(); // Wait until queue/server is readyqueue.close(); // Close TCP connection (embedded: write buffered adds to SQLite)await queue.pauseAsync(); // Stop new pulls and wait for the brokerawait queue.resumeAsync(); // Resume the queueconst n = await queue.drainAsync(); // Remove waiting/delayed jobs, return countawait queue.obliterateAsync(); // Remove all queue dataawait queue.removeAsync('job-id'); // Remove one job and wait for the brokerawait queue.waitUntilReady();await queue.disconnect(); // Flush pending adds and close the connectionqueue.pause() # Workers stop pullingqueue.resume() # Back to normaln = queue.drain() # Remove all waiting/delayed jobs, get removed countqueue.obliterate() # Remove ALL queue data
queue.remove("job-id") # Remove one job
queue.wait_until_ready() # Wait until the server is reachablequeue.close() # Close the TCP connection$queue->pause(); // Workers stop pulling$queue->resume(); // Back to normal$n = $queue->drain(); // Remove all waiting/delayed jobs, get removed count$queue->obliterate(); // Remove ALL queue data
$queue->remove('job-id'); // Remove one job
$queue->close(); // Close the TCP connectionqueue.Pause() // Workers stop pullingqueue.Resume() // Back to normaln, _ := queue.Drain() // Remove all waiting/delayed jobs, get removed countqueue.Obliterate() // Remove ALL queue data
queue.Remove("job-id") // Remove one job
queue.Close() // Close the TCP connectionqueue.pause()?; // Workers stop pullingqueue.resume()?; // Back to normallet n = queue.drain()?; // Remove all waiting/delayed jobs, get removed countqueue.obliterate()?; // Remove ALL queue data
queue.remove("job-id")?; // Remove one job
queue.close(); // Close the TCP connection:ok = Bunqueue.Queue.pause(queue) # Workers stop pulling:ok = Bunqueue.Queue.resume(queue) # Back to normal{:ok, n} = Bunqueue.Queue.drain(queue) # Remove all waiting/delayed jobs, get removed count:ok = Bunqueue.Queue.obliterate(queue) # Remove ALL queue data
:ok = Bunqueue.Queue.close(queue) # Close the TCP connectionGotcha: in TCP mode the fire-and-forget forms return before the server has processed them. If you drain or obliterate and immediately add new jobs, the wipe can land after the add and delete the new job. Use the Async variants when the next step depends on the command being done. A fire-and-forget command that fails (for example, the broker is unreachable) is logged as one line naming the command and the queue and never crashes the process; the Async variants reject to the caller instead.
Remove one job
Section titled “Remove one job”removeAsync(id) and job.remove() remove a job that is waiting, delayed, prioritized or waiting for children, and also a completed job: its data and its result are deleted, so “read the result, then make sure the job is gone” works. A payload-free completion record stays behind (the same one removeOnComplete keeps), so jobs that depend on the removed one still run.
const result = await job.waitUntilFinished(null, 30_000); // read the result firstawait job.remove(); // then delete data and resultawait queue.getJobState(job.id); // 'unknown'await job.remove(); // a second call still resolvesAn active job (including the job a processor is running, when it calls job.remove() on itself) and a failed job are never removed: the awaited call rejects with the job’s state, for example Job cannot be cancelled: not in queue (current state: active). Removing a job that does not exist resolves, so cleanup code can call it twice. Failed jobs leave through the DLQ. The fire-and-forget queue.remove(id) cannot report a refusal; use removeAsync when it matters. On PostgreSQL, a waiting job that another live job still depends on is refused too, with Job cannot be cancelled: not in queue (current state: waiting); remove the dependent job first.
Connected to a broker of version 2.9.13 or earlier, which answers every refusal (an active, failed or completed job too) with Job not found or cannot be cancelled, the client reads the job’s state before deciding: the call resolves only when the job no longer exists, and otherwise rejects with Job <id> cannot be removed (current state: active) (or the job’s other state). A completed job is never removed by such a broker.
Removing a job deletes the job, its result and what the broker holds for it in memory. It does not rewrite history: events already recorded in the queue’s bounded event journal (queue_events on SQLite, bunqueue_events on PostgreSQL), such as the completed event that carried the return value, stay there until the journal’s retention trims them, exactly as for a job added with removeOnComplete. To drop older journal entries sooner, call queue.trimEvents(maxLength) (see Metrics).
Maintenance
Section titled “Maintenance”// Remove completed jobs older than 1 hour, max 100 (async works in both modes)const removed = await queue.cleanAsync(3600000, 100, 'completed');
// Promote delayed jobs to waiting nowconst promoted = await queue.promoteJobs({ count: 50 });
// Re-queue failed jobs from the DLQawait queue.retryJobs({ state: 'failed', count: 100 });
// Re-queue completed jobs through the same selector contractawait queue.retryJobs({ state: 'completed', count: 100, timestamp: Date.now() - 3600000, // completed at least one hour ago});
// Direct completed-job helpers (e.g. after a logic change)const count = await queue.retryCompletedAsync(); // all completed, use with careconst one = queue.retryCompleted('job-id-123'); // one job (sync, embedded; TCP returns 0)// Remove completed jobs older than 1 hour, max 100 (async works in both modes)const removed = await queue.cleanAsync(3600000, 100, 'completed');
// Promote delayed jobs to waiting nowconst promoted = await queue.promoteJobs({ count: 50 });
// Re-queue failed jobs from the DLQawait queue.retryJobs({ state: 'failed', count: 100 });
// Re-queue completed jobs through the same selector contractawait queue.retryJobs({ state: 'completed', count: 100, timestamp: Date.now() - 3600000, // completed at least one hour ago});
// Direct completed-job helpers (e.g. after a logic change)const count = await queue.retryCompletedAsync(); // all completed, use with careconst one = await queue.retryCompletedAsync('job-id-123'); // one job; returns the broker count# Remove completed jobs older than 1 hour, max 100removed = queue.clean(3600000, 100, "completed")
# Promote delayed jobs to waiting nowpromoted = queue.promote_jobs(50)
# Re-queue failed jobs from the DLQqueue.retry_jobs("failed", 100)
# Re-queue completed jobs (e.g. after a logic change)queue.retry_completed() # all completed, use with carequeue.retry_completed("job-id-123") # one job// Remove completed jobs older than 1 hour, max 100 (returns removed job ids)$removed = $queue->clean(3600000, 100, 'completed');
// Promote one delayed job to waiting now$queue->promote('job-id');
// Re-queue one failed job (failed -> waiting)$queue->retryJob('job-id');// Remove completed jobs older than 1 hour, max 100 (returns removed job ids)removed, _ := queue.Clean(3600000, 100, "completed")
// Promote one delayed job to waiting nowqueue.Promote("job-id")
// Re-queue one failed job (failed -> waiting)queue.RetryJob("job-id")// Remove completed jobs older than 1 hour, max 100 (returns removed job ids)let removed = queue.clean(3_600_000, 100, "completed")?;
// Promote one delayed job to waiting nowqueue.promote("job-id")?;
// Re-queue one failed job (failed -> waiting)queue.retry_job("job-id")?;# Remove completed jobs older than 1 hour, max 100 (returns removed job ids){:ok, removed} = Bunqueue.Queue.clean(queue, 3_600_000, 100, "completed")
# Promote all delayed jobs to waiting now:ok = Bunqueue.Queue.promote_jobs(queue)
# Re-queue one failed job (failed -> waiting):ok = Bunqueue.Queue.retry_job(queue, "job-id")Bulk retryJobs, retryCompleted, and counted promoteJobs are available in TypeScript and Python; PHP, Go, and Rust act per job (promote, retryJob); Elixir exposes an uncounted bulk promote_jobs/1.
For SQLite queues, completed cleanup queries the database rather than only the
bounded in-memory cache. It removes the oldest eligible rows first with id as
a deterministic tie-breaker, so repeated calls page through all retained
history even when it exceeds maxCompletedJobs. The job, result, and related
flow-failure rows are deleted in one transaction; the returned IDs are exactly
the committed deletions. A completed dependency whose result is still needed
by a live consumer is skipped until that consumer is removed or resolved.
Retrying a completed job starts a new waiting execution. Its previous
returnvalue, progress/message, processedOn, and finishedOn are cleared;
attempts restart at zero, while the diagnostic stacktrace and timeline history
remain available. For persisted queues, that reset and removal of the old
result are atomic in the selected backend: one SQLite transaction in
single-broker mode, or a PostgreSQL transaction with its durable event in
multi-broker mode. The cleared state therefore survives broker restart.
Where to go next
Section titled “Where to go next”| Guide | What it covers |
|---|---|
| Queue API | Create a queue in embedded or TCP mode |
| Adding Jobs | add, addBulk, priorities, delays, durability |
| Deduplication and Idempotent Job Adds | Idempotent adds, dedup keys, custom job ids |
| Querying Jobs | Fetch jobs, states, counts and results |
| Progress, Job Logs and Dependencies | Progress, per-job logs and dependencies |
| Queue Rate Limiting and Global Concurrency | Rate limits and global concurrency caps |
| Job Schedulers from the Queue | Named repeatable schedules from the queue |
| DLQ Operations from the Queue Object | Failed-job operations from the Queue object |
| Workers, Stats and Metrics from the Queue | Registered workers, stats and metrics windows |
| Namespaces, Auto-Batching and Store-and-Forward | Namespaces, auto-batching, store-and-forward |
| JobOptions Reference | Every JobOptions field, with defaults |