Aborted blocking commands leave dangling sockets
Nobody has claimed this yet.
- 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.blPopallows the process to exit naturally - setting
isolated: falsemakes the code get stuck awaitingclient.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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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