#4656·bullmq

Worker.close() never resolves when Redis is unreachable, so the process never exits

Author: petarzarkovCreated Aug 29, 2026Updated Sep 12, 2026

Description

Worker.close() never resolves when the Redis server is unreachable, and the process never exits.

The worker is parked in ioredis' reconnecting state, so close() awaits an end event that is never emitted. This is the same un-timed await disconnecting that #4065 identifies for pause(), reached by a different route: a single worker and a server that was never reachable, rather than several workers on a healthy server.

Reproduction

Nothing listening on the port. No Redis required to reproduce.

javascript
import { Worker } from 'bullmq';

const worker = new Worker('probe', async () => {}, {
  connection: { host: '127.0.0.1', port: 6399, maxRetriesPerRequest: 0 },
});

await new Promise((resolve) => setTimeout(resolve, 300));
await worker.close();
console.log('close() resolved; the process should now exit on its own');

Expected: close() resolves and the process exits 0.

Actual: the line never prints, ECONNREFUSED repeats indefinitely, and the process has to be killed.

Control

The identical script against a reachable Redis on the same port prints the line and exits 0. The only variable is whether the server answers.

Server on 127.0.0.1:6399 Node 24.18.0 Bun 1.4.0
reachable exits 0 exits 0
nothing listening hangs hangs

Diagnosis

Racing close() against a 5 s timer, and reading the active resources afterwards:

OUTCOME: close() still pending after 5s
active resources: ["PipeWrap","Timeout","Timeout","Timeout"]

close() is pending rather than rejected, and what holds the loop is three armed ioredis retry timers with no live socket. That matches dist/esm/classes/redis-connection.js:

javascript
const disconnecting = new Promise((resolve, reject) => {
  client.once('end', resolve);
  client.once('error', reject);
});
client.disconnect();
await disconnecting;   // no timeout

While the client is reconnecting there is no socket to end, so neither listener fires.

close(true), disconnect() after close(), and both together were each measured and none of them releases the loop, so there is no userland workaround short of process.exit.

Not runtime or client specific

Reproduced on Node 24.18.0 and on Bun 1.4.0, and with both an ioredis connection and createBunRedisClient. All four combinations hang identically, so this is not a Bun or an adapter issue.

A Queue is unaffected: new Queue(...), add(), close() against the same refused port resolves and exits 0. Only the Worker hangs.

Environment

  • bullmq 6.3.2 (also reproduced on 6.0.5)
  • ioredis 6.0.0
  • Node 24.18.0, Bun 1.4.0
  • Linux x64

Related

  • #4065 - pause() hanging on the same un-timed await disconnecting, with a healthy server and several workers.
  • #4586 - describes a blocking client parked in reconnecting, which is the state this reproduction reaches.

Found while investigating why a service holding a Worker would not shut down on SIGTERM when its Redis was down.