Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Use BullMQ’s QueueEvents when one or more services need to observe job lifecycle events across every worker on a queue. Workers divide the work; they do not each receive a copy of every job. QueueEvents provides queue-wide event observation using Redis Streams, without adding a separate message broker for that purpose.
What “fan-out” means in BullMQ
BullMQ has two different patterns that can sound like fan-out. Workers consume jobs from a shared queue, so multiple workers distribute processing rather than each getting its own copy. Separately, a QueueEvents listener can observe lifecycle events generated by jobs handled across those workers.
As an Amazon Associate I earn from qualifying purchases.
Ordinary Queue and Worker event listeners are local to their process. A process that needs queue-wide visibility should use QueueEvents. If several independent services need to observe those events, each service can create its own QueueEvents instance and register the event types it needs. BullMQ’s Events guide describes the event scope and implementation.
Recommended Free Tools
Set up a queue-wide event listener
Construct a QueueEvents instance with the queue name and Redis connection used by your application, then register handlers for the events that matter to the consumer. This TypeScript example illustrates the documented API; adapt the connection configuration to your application.
#1 Best Overall
import { QueueEvents } from 'bullmq';
const queueEvents = new QueueEvents('orders', { connection });
queueEvents.on('completed', ({ jobId, returnvalue }) => {
notifyConsumers({ type: 'completed', jobId, returnvalue });
});
queueEvents.on('failed', ({ jobId, failedReason }) => {
notifyConsumers({ type: 'failed', jobId, failedReason });
});
await queueEvents.waitUntilReady();
// On application shutdown:
await queueEvents.close();
- Create the listener for the queue name with the appropriate Redis connection.
- Register handlers for the lifecycle events the service needs, such as
completed,failed, orprogress. - Wait for readiness before relying on it, and close the instance during shutdown to release its Redis connection.
- Handle errors from workers and listeners. BullMQ warns that an unhandled worker error can stop processing.
A single instance can dispatch events to several callbacks within its process. Separate services that need independent observation should each instantiate their own listener.
Read event payloads without assuming they contain a Job
QueueEvents payloads are compact event data, not hydrated Job objects. Depending on the event, the payload commonly contains jobId and fields such as returnvalue, failedReason, or progress data. If a consumer genuinely needs the full job, retrieve it by ID; BullMQ’s quick start documents Job.fromId as an option. BullMQ Quick Start
Understand the delivery and retention limits
BullMQ documents QueueEvents as implemented with Redis Streams. Its Events guide says this provides delivery guarantees across disconnections that standard pub/sub does not provide. That does not make the event stream an unlimited archive: the stream is auto-trimmed to approximately 10,000 events by default. Configure streams.events.maxLen to change the maximum, and size retention against expected event volume and the downtime a listener may experience. BullMQ Events guide
These are queue lifecycle events, not a substitute for a separately designed durable business-event system. If downstream consumers must preserve every business fact independently of stream trimming or application downtime, define that requirement and its persistence and recovery behavior explicitly.
Rank #3
Use a different design when every consumer needs the job
If the requirement is for multiple consumers to process a separate copy of every job, QueueEvents is not job duplication: it observes lifecycle changes. BullMQ workers distribute jobs among themselves, and BullMQ recommends multiple workers for concurrency and availability. Design explicit job fan-out for independent processing rather than treating event observation as a copy of the work. BullMQ Workers guide BullMQ Queues guide
Redis is still part of the architecture
Using QueueEvents avoids adding a separate broker for queue-wide lifecycle observation, but BullMQ still requires Redis: jobs are stored in Redis, and the official quick start requires a running Redis service. BullMQ Quick Start
Publish custom events when lifecycle events are not enough
For event names beyond job lifecycle changes, BullMQ documents QueueEventsProducer for publishing custom events that QueueEvents consumers can subscribe to. This keeps the same event-observation approach while allowing application-specific event types. BullMQ Events guide
Choose the listener by scope
| Approach | What it observes | Payload | Disconnection and retention |
|---|---|---|---|
| Worker-local event listener | Events in that worker’s process | Worker event callbacks; not a queue-wide observer | Local callback; does not provide the QueueEvents Redis Stream behavior |
QueueEvents |
Lifecycle events across workers on the queue | Compact event fields, commonly including jobId, not a full Job |
Redis Streams; auto-trimmed to approximately 10,000 events by default, configurable with streams.events.maxLen |
The documentation pages cited here describe BullMQ APIs but do not specify a particular package version. Check the documentation matching your installed BullMQ version before relying on version-specific behavior.
Quick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

