Skip to content
Get started
Get started
Worker Lifecycle: Pause, Resume, Graceful Shutdown
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.

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.

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