-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
async_hooks: discourage AsyncLocalStorage.disable #58065
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
--async-context-frame
Codecov ReportAll 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()`.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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';
const common = require('../common');
const { AsyncLocalStorage } = require('async_hooks');
const { gcUtil, gcUntil } = require('../common/gc');
let weakRef;
{
const als = new AsyncLocalStorage();
let obj = {};
als.run(obj, () => {
setInterval(() => {}, 1000).unref();
});
als.disable();
weakRef = new WeakRef(obj);
obj = null;
}
// This assertion fails.
gcUntil('als value', () => {
return weakRef.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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
`asyncLocalStorage` can be garbage collected. This does not apply to stores | |
provided by the `asyncLocalStorage`, as those objects are garbage collected | |
along with the corresponding async resources. |
When
--async-context-frame
is enabled (and by default in v24), thereshould be no need to manually call
asyncLocalStorage.disable()
.Nevertheless, a general
AsyncLocalStorage
use case will construct anAsyncLocalStorage
at 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