Uh oh!
There was an error while loading. Please reload this page.
async_hooks: discourage AsyncLocalStorage.disable - #58065
Conversation
--async-context-frameCodecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@## main #58065 +/- ##
==========================================
- Coverage 90.21% 90.21% -0.01%
==========================================
Files 630 630 Lines 186391 186397 +6 Branches 36610 36612 +2 ==========================================
+ Hits 168146 168150 +4 + Misses 11066 11053 -13 - Partials 7179 7194 +15
🚀 New features to boost your workflow:
|
When `--async-context-frame` is enabled (and by default in v24), there should be no need to manually call `asyncLocalStorage.disable()`.
Qard
left a comment
There was a problem hiding this comment.
The disable() function is not just for letting the store instance be GC'd, it's also to remove the associated entry from the AsyncContextFrame, allowing the value to be GC'd too. This is still a valid use case.
With this change, the symbol is held alive instead, and the value remains in the map.
This statement contradicts with the document: Lines 228 to 230 in fc054bb The document says On the tip of main, the behavior also aligns with the doc. It can be verified with a test script: // Flags: --async-context-frame --expose-gc'use strict';constcommon=require('../common');const{ AsyncLocalStorage }=require('async_hooks');const{ gcUtil, gcUntil }=require('../common/gc');letweakRef;{constals=newAsyncLocalStorage();letobj={};als.run(obj,()=>{setInterval(()=>{},1000).unref();});als.disable();weakRef=newWeakRef(obj);obj=null;}// This assertion fails.gcUntil('als value',()=>{returnweakRef.deref()==null;}).then(common.mustCall());That is, with |
| provided by the `asyncLocalStorage`, as those objects are garbage collected | ||
| along with the corresponding async resources. | ||
| There is no need to call this method in order to get an `asyncLocalStorage` | ||
| instance from being garbage-collected. |
There was a problem hiding this comment.
The wording here is a bit off. If the intention is to say that disable() is not needed to allow the ALS instance to be garbage collected then I would actually suggest just dropping this first sentence.
There was a problem hiding this comment.
This only works with --async-context-frame. Given that --async-context-frame is the default option now, it is simply discouraged to use disable.
| `asyncLocalStorage.disable()` is required before the `asyncLocalStorage` itself | ||
| can be garbage collected. However, this does not apply to stores provided by | ||
| the `asyncLocalStorage`, as those objects are garbage collected along with the | ||
| corresponding async resources. |
There was a problem hiding this comment.
This second sentence here is rather confusing if you're not familiar with ALS as a whole. I'm not sure it adds a lot of value here.
There was a problem hiding this comment.
It is an important trait of disable that it does not make all entered stores GC-able. It is an existing document sentence that re-organized in this PR:
Lines 228 to 230 in fc054bb
Flarna
commented
May 5, 2025
I'm still not really clear what the expectation of I doubt we find a way to remove all stores from all In the old implementation In the new implementation |
Qard
commented
May 9, 2025
Depends on the use, but yes, it's not a great API. It's really only implemented to try to keep feature parity with the async_hooks implementation. But the actual usefulness is debatable. More could probably be done to bring the behaviour in line with the async_hooks implementation, but discouraging its use or possibly even deprecating it may also be reasonable. I would say it's not quite the same as |
Flarna
commented
May 10, 2025
I agree Having an API to just remove the strong reference from the current active I fear a global working |
Qard
commented
Jun 2, 2025
Given that it's marked experimental currently, and the ergonomics are...not the best...I think it's probably fine to warn against its use, but perhaps provide more clarity about why it continues to exist rather than just being entirely deprecated? Could also just deprecate it anyway, as I'm not sure if anyone is even using it. 🤔 |
This pull request has been marked as stale due to 90 days of inactivity. |
When
--async-context-frameis enabled (and by default in v24), thereshould be no need to manually call
asyncLocalStorage.disable().Nevertheless, a general
AsyncLocalStorageuse case will construct anAsyncLocalStorageat module-top-level, so it will never get GC-ed anyway.If calling
asyncLocalStorage.disable()and enable it again, issues like#53037 will rise. So its use should be discouraged.
Refs: #58019
/cc @nodejs/diagnostics