Bull queues emit events throughout the job lifecycle, allowing you to monitor progress, handle completions, react to failures, and track queue state changes.
Local events fire only on the specific queue instance where a listener is registered:
const queue = new Queue('myqueue');// This listener only fires for jobs processed by THIS workerqueue.on('completed', (job, result) => { console.log(`Job ${job.id} completed with result:`, result);});
Global events fire across all queue instances connected to the same Redis database. Prefix event names with global::
// This listener fires for jobs completed by ANY workerqueue.on('global:completed', (jobId, result) => { console.log(`Job ${jobId} completed with result:`, result);});
Global events pass the job ID instead of the full job instance. Use Queue#getJob(jobId) to retrieve the job object if needed.
From the REFERENCE.md (~/workspace/source/REFERENCE.md:1118-1156):
// Local events pass the job instance...queue.on('progress', function (job, progress) { console.log(`Job ${job.id} is ${progress * 100}% ready!`);});queue.on('completed', function (job, result) { console.log(`Job ${job.id} completed! Result: ${result}`); job.remove();});// ...whereas global events only pass the job ID:queue.on('global:progress', function (jobId, progress) { console.log(`Job ${jobId} is ${progress * 100}% ready!`);});queue.on('global:completed', function (jobId, result) { console.log(`Job ${jobId} completed! Result: ${result}`); queue.getJob(jobId).then(function (job) { job.remove(); });});
queue.on('active', (job, jobPromise) => { console.log(`Job ${job.id} is now active`); // You can cancel the job using jobPromise.cancel() if needed});// Global versionqueue.on('global:active', (jobId) => { console.log(`Job ${jobId} started globally`);});
From the source (~/workspace/source/lib/queue.js:1216-1217):
// Local event with jobPromise so that we can cancel job.utils.emitSafe(this, 'active', job, jobPromise, 'waiting');
Fires when a job is detected as stalled (process crashed or event loop blocked):
queue.on('stalled', (job) => { console.log(`Job ${job.id} has stalled and will be reprocessed`); // Alert your monitoring system!});// Global versionqueue.on('global:stalled', (jobId) => { console.warn(`Job ${jobId} stalled globally`);});
Always monitor the stalled event in production. Frequent stalled jobs indicate problems with your processor (crashes or blocking code) and can lead to jobs being processed multiple times.