BullMQ is a significant evolution from its predecessor, Bull. It was built to improve upon some aspects of Bull, while retaining many of its useful features.
Here are some key differences:
More structured codebase: BullMQ has a more organized codebase than Bull which makes it easier to maintain and contribute to.
Typescript support: One of the appealing aspects of BullMQ over Bull is that it's written in TypeScript, providing strong typing, which can be beneficial for large, complex projects.
Job Events Model: In Bull, job events were implemented over Pub-Sub mechanism, whereas BullMQ uses Streams for job events. This provides better reliability and performance.
Separated Workers and Event listeners: The worker and event listener processes are separate in BullMQ, which helps to prevent event listeners from blocking job processing. In Bull, these two were not separated.
Scheduler Process: BullMQ introduces a new process called "Scheduler" which is used to move delayed jobs into the waiting list when they are due. This was handled within the standard worker processes in Bull.
Job Dependencies: BullMQ supports job dependencies which wasn't present in Bull. This means you can set up jobs that won't start until other jobs complete.
Priority Queueing: Both Bull and BullMQ support priority queueing, but BullMQ extends this with additional features such as rate-limited queues and scheduling.
Let's look at a simple code example that highlights some differences. In Bull:
In the above example, while adding a job to the queue in BullMQ, we pass also the name of the job which wasn't present in Bull.