Skip to content
Get started
Get started
Worker Lifecycle: Pause, Resume, Graceful Shutdown
View Markdown
guide · worker

Stopping without dropping work.

Deploys are the most common cause of stalled jobs. Closing a worker properly lets in-flight jobs finish and be acknowledged before the process exits.

worker.run(); // Start processing (if created with autorun: false)
worker.pause(); // Stop pulling new jobs
worker.resume(); // Resume
await worker.close(); // Wait for active jobs, then stop
await worker.close(true); // Force close immediately

Pausing stops new pulls; it does not interrupt processors already running or release jobs already buffered by the Worker. Lease-renewal and worker-registration heartbeats therefore continue while paused. resume() reuses those heartbeat loops, and repeated pause/resume cycles do not create additional timers.

close(true) stops owning the active delivery immediately; it does not forcibly cancel JavaScript already running inside the processor. If that processor later returns or throws, the Worker discards the late outcome without sending ACK or FAIL. The broker can therefore recover the unfinished job through disconnect, lock-expiry, or stall handling instead of accepting a result from a closed worker. Use plain close() when the current result must be committed before shutdown.

Processing timeouts follow the same generation rule during normal operation. The broker owns the deadline and claims the active generation atomically. If a processor returns or throws after that claim, the Worker receives an explicit ignored outcome and suppresses its local completed, failed, and ACK/FAIL error events. A retry’s newer lease is independent and can complete normally.

Cancel active processors cooperatively (Bun)

Section titled “Cancel active processors cooperatively (Bun)”

Every Bun processor receives an AbortSignal in its second argument. Cancel one delivery or every active delivery owned by this Worker:

const worker = new Worker('downloads', async (job, context) => {
return await fetch(job.data.url, { signal: context?.signal });
});
worker.cancelJob(jobId, 'request withdrawn'); // false unless this Worker is currently executing that job (pulled-but-not-started jobs return false too)
worker.cancelAllJobs('service is shutting down');
worker.isJobCancelled(jobId); // true while its cancelled delivery remains active here

Cancellation aborts the signal and emits cancelled({ jobId, reason }). A Promise processor must pass that signal to fetch or another cancellable API, or check signal.aborted; JavaScript cannot forcibly stop a Promise that ignores it. Structural Observable processors are unsubscribed automatically. The resulting processor rejection follows normal failure/retry handling.

close(true) is different: it relinquishes active delivery ownership and suppresses late outcomes so broker recovery can redeliver. Use cancellation when the processor should observe and handle an abort; use forced close when the process must stop owning work immediately.

For a clean process exit, hook your runtime’s shutdown signal; in the Bun client, also shut down the shared machinery:

import { shutdownManager, closeSharedTcpClient } from 'bunqueue/client';
process.on('SIGINT', async () => {
await worker.close();
shutdownManager(); // Embedded mode: flush writes, close SQLite
closeSharedTcpClient(); // TCP mode: close the shared connection pool
process.exit(0);
});

In Rust and Elixir, calling worker.stop() / Bunqueue.Worker.stop(worker) from another thread or process makes the blocking run loop drain and return; there is no shared client machinery to tear down.

GuideWhat it covers
WorkerCreate a worker and process your first job
Worker Concurrency and Batch PullingRun jobs in parallel and pull them in batches
The Job Object Inside a Worker ProcessorEverything the processor receives and can do
Worker Eventscompleted, failed, stalled and the rest
Worker Error Handling, Retries and BackoffRetries, backoff, timeouts and giving up
Heartbeats, Stall Detection and Lock OwnershipHeartbeats, stall recovery and lock ownership
SandboxedWorkerExperimental isolation for CPU-heavy handlers
WorkerOptions ReferenceEvery WorkerOptions field, with defaults