You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Request signal isn't aborted after garbage collection #55428
Passing a signal to Request() and aborting it does not cause the underlying request signal to be aborted after it's been garbage collected. This leads to issues where you want to listen on the request signal even after the request itself falls out of scope - e.g., the request is instantiated with an abort controller signal and downstream code is waiting for that signal to be aborted via request.signal.
Reproducible By
Run the following using node --expose-gc main.js:
constac=newAbortController();ac.signal.addEventListener("abort",()=>{console.log("ac signal aborted");});constrequest=newRequest("https://google.ca",{signal: ac.signal});request.signal.addEventListener("abort",()=>{console.log("request signal aborted");});setTimeout(()=>{global.gc();ac.abort();},0);
Expected Behavior
ac signal abortedandrequest signal aborted should be logged to the console.
Instead, only ac signal aborted is logged.
Environment
Latest node and undici. Tried it in some older versions as well.
Additional context
A few folks are running into this while trying to close event stream requests in the remix web framework. The underlying requests are never closed because the signal doesn't get aborted.
Therefore undici seems to be working properly? Since the parent AbortSignal is aborted, the dependent signal (ie. the one created for every instance of Request) can be garbage collected.
@KhafraDev - I would expect the dependent signal to also be aborted after the parent signal is aborted & before it is garbage collected. Currently, the dependent signal seems to stop working when the request itself is garbage collected, not when its parent signal is garbage collected. Perhaps I'm missing something?
Currently when a Request is collected, the signal is removed (see nodejs/undici#1113)
must not be garbage collected while its source signals is non-empty and it has registered event listeners for its abort event or its abort algorithms is non-empty.
There is a bug here - we shouldn't be removing the signal if there are registered 'abort' event listeners. I will have a PR in a few hours unless the approach I'm thinking of doesn't work.
Reacted by Justin Vaillancourt, Toni Villena and Mattias Buelens
constac=newAbortController();ac.signal.addEventListener("abort",()=>{console.log("ac signal aborted");});constrequest={signal: (()=>{constourAc=newAbortController()ourAc.signal.addEventListener('abort',()=>console.log('called'),{once: true})returnourAc.signal})()}request.signal.addEventListener("abort",()=>{console.log("request signal aborted");});setTimeout(()=>{global.gc();ac.abort();},0);
As I went through the implementation, I wanted to know whether this particular line is resulting in signal to be removed by GC or not. @mcollina@KhafraDev@ronag
Activity
ronag commentedon Sep 26, 2024
@KhafraDev
ronag commentedon Sep 26, 2024
https://dom.spec.whatwg.org/#abort-signal-garbage-collection
KhafraDev commentedon Sep 26, 2024
Therefore undici seems to be working properly? Since the parent AbortSignal is aborted, the dependent signal (ie. the one created for every instance of Request) can be garbage collected.
jvaill commentedon Sep 26, 2024
@KhafraDev - I would expect the dependent signal to also be aborted after the parent signal is aborted & before it is garbage collected. Currently, the dependent signal seems to stop working when the request itself is garbage collected, not when its parent signal is garbage collected. Perhaps I'm missing something?
KhafraDev commentedon Sep 26, 2024
Currently when a Request is collected, the signal is removed (see nodejs/undici#1113)
There is a bug here - we shouldn't be removing the signal if there are registered 'abort' event listeners. I will have a PR in a few hours unless the approach I'm thinking of doesn't work.
KhafraDev commentedon Sep 27, 2024
I believe this is a bug in node -
Only
ac signal abortedis printed.ronag commentedon Sep 27, 2024
@benjamingr
mcollina commentedon Sep 28, 2024
cc @nodejs/web-standards
mcollina commentedon Oct 17, 2024
transferred to node
zachrip commentedon Dec 20, 2024
Is there any work being done to resolve this?
mcollina commentedon Jan 14, 2025
@zachrip not at the moment, it's a bug in Node.js. Specifically https://dom.spec.whatwg.org/#abort-signal-garbage-collection is not implemented.
Tseian commentedon Mar 13, 2026
@KhafraDev After GC removed the object request, the value of member
signalwill be removed by GC too.SudhansuBandha commentedon Apr 6, 2026
node/deps/undici/src/lib/web/fetch/request.js
Line 431 in e775989
As I went through the implementation, I wanted to know whether this particular line is resulting in
signalto be removed by GC or not.@mcollina @KhafraDev @ronag
fix(webapp): fix Redis connection leak in realtime streams and broken…
fix(webapp): fix Redis connection leak in realtime streams and broken…
fix(webapp): fix Redis connection leak in realtime streams and broken…
fix(webapp): fix Redis connection leak in realtime streams and broken…
fix(webapp): use getRequestAbortSignal() for dashboard stream routes
fix(webapp): use getRequestAbortSignal() for dashboard stream routes
fix(webapp): use getRequestAbortSignal() for dashboard stream routes
fix(webapp): use getRequestAbortSignal() for dashboard stream routes
chore: release v4.4.5 (#3406)
fix(webapp): use getRequestAbortSignal() for dashboard stream routes
fix(webapp): use getRequestAbortSignal() for dashboard stream routes
fix(webapp): use getRequestAbortSignal() for dashboard stream routes
fix: replace SDK AbortSignal.timeout with application-level AbortCont…
chore: bump umm-actually to v0.3.9 (#453)
chore: bump umm-actually to v0.3.9 (#11)