Graceful shutdown of BullMQ workers prevents Node JS from exiting

968 Views Asked by At

I follow the recommendation here and also this thread and I use the following code in order to gracefully shutdown BullMQ workers in my development environment on Ubuntu:

  const handleTermination = async () => {
    log.info(`Gracefully shutting down worker for queue '${name}'.`);
    await worker.close();
  };
  process.on('SIGTERM', handleTermination).on('SIGINT', handleTermination);

However the above code prevents the app from ending. The result in the console is the following for 3 consecutive Ctrl+C:

^C[2023-04-23T16:15:46.423] [INFO] development - Gracefully shutting down worker for queue 'X'.
[2023-04-23T16:15:46.423] [INFO] development - Gracefully shutting down worker for queue 'Y'.
^C[2023-04-23T16:15:47.075] [INFO] development - Gracefully shutting down worker for queue 'X'.
[2023-04-23T16:15:47.075] [INFO] development - Gracefully shutting down worker for queue 'Y'.
^C[2023-04-23T16:15:47.793] [INFO] development - Gracefully shutting down worker for queue 'X'.
[2023-04-23T16:15:47.793] [INFO] development - Gracefully shutting down worker for queue 'Y'.

Obviously the process is still there forever and can only be finished with kill -9. Note that there is no pending job.

What I am missing here?

Of course the problem is gone when I use process.exit() but I understand that this is not the recommended handling.

1

There are 1 best solutions below

0
rveerd On

A Node.js process will exit when there is no more work to be done. See this answer for details.

BullMQ creates a connection to the Redis database when you create Worker objects. But it also creates a connection when you create Queue objects. To gracefully exit Node.js you have to close all connections. You have to call close() both on the workers and the queues.

Another option is to create the Redis connection yourself and pass it to the Queue constructor. The queue object uses the passed connection and does not create its own connection. In this case, you only have to close the Redis connection.

import { Queue } from 'bullmq';
import { Redis } from 'ioredis';

const connection = new Redis();
const queue = new Queue('foo', { connection });

// create more queues with the same connection...

// post jobs to queues...

connection.quit();

Note that the same does not work for worker objects. A worker object creates additional connections to the Redis database. See the documentation for details.

You can easily see all active connections to the Redis database using redis-cli:

$ redis-cli CLIENT LIST