redis / redis/node-redis

Aborted blocking commands leave dangling sockets

Open
#1,889 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug
Dominant language
TypeScript
Stars
17.6k
Forks
2k
Avg merge
2d 3h
Merged PRs (30d)
40

Description

Environment:

  • Node.js Version: 16.13.2
  • Redis Server Version: 6.2.6
  • Node Redis Version: redis@4.0.3
  • Platform: MacOS 11.6.1

Abort signals appear to result in sockets being left open. Consider this code:

"use strict";

const redis = require("redis");
const client = redis.createClient();

client.connect().then(() => {
  const abortController = new AbortController();
  const options = redis.commandOptions({ signal: abortController.signal, isolated: true });

  client.blPop(options, 'test-list', 0).catch(error => {
    console.log('error is AbortError', error instanceof redis.AbortError);
  });

  setTimeout(async () => {
    abortController.abort();
    await client.quit();
    console.log("client quit")
  }, 100);
});

The abort signal triggers the expected console log about the AbortError. However, the node process will not exit. The second log also happens, so we know that the client thinks it has cleared itself up. client.disconnect() yields the same result.

More observations:

  • commenting out the client.blPop allows the process to exit naturally
  • setting isolated: false makes the code get stuck awaiting client.quit, which it shouldn't (the abort should cancel the only command the client was handling)

Augmenting this code with a utility like wtfnode shows an open socket to redis which should be closed (on various ports on the left):

[WTF Node?] open handles:
- File descriptors: (note: stdio always exists)
  - fd 1 (tty) (stdio)
  - fd 2 (tty) (stdio)
- Sockets:
  - (?:?) -> localhost:? (destroyed)
  - 127.0.0.1:50820 -> 127.0.0.1:6379
- Timers:
  - (100 ~ 100 ms) (anonymous) @ /Volumes/code/.../test_bug.js:15

My guess (which is probably way off) is that the destroyed socket is the client directly created and quit in the code, but the indirectly created isolated client is not being cleaned up.

There's not much information in the docs about abort signals. It may be I've stumbled upon some API which isn't quite ready yet. My apologies if so!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reproduction in test_bug.js and trace abort handling for the isolated client created by commandOptions. Check how the open Redis socket is cleaned up after AbortError, then verify that client.quit() or client.disconnect() allows the Node.js process to exit in both isolated and non-isolated cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js, redis
Domain
backend, databases, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.