-
Notifications
You must be signed in to change notification settings - Fork 98
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
fix: adjust async_hooks cls behavior #734
Conversation
this.hook = (require('async_hooks') as AsyncHooksModule).createHook({ | ||
// Store a reference to the async_hooks module, since we will need to query | ||
// the current AsyncResource ID often. | ||
this.ah = require('async_hooks') as AsyncHooksModule; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
src/cls/async-hooks.ts
Outdated
} | ||
|
||
setContext(value: Context): void { | ||
this.currentContext.value = value; | ||
this.contexts[this.ah.executionAsyncId()].value = value; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
src/cls/async-hooks.ts
Outdated
const boundContext = this.currentContext.value; | ||
const that = this; | ||
// Capture the context of the current AsyncResource. | ||
const boundContext = this.contexts[outerId]; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Codecov Report
@@ Coverage Diff @@
## master #734 +/- ##
==========================================
+ Coverage 90.88% 90.93% +0.05%
==========================================
Files 30 30
Lines 1568 1577 +9
Branches 304 307 +3
==========================================
+ Hits 1425 1434 +9
Misses 59 59
Partials 84 84
Continue to review full report at Codecov.
|
src/cls/async-hooks.ts
Outdated
// constructor, rather than upon module load. | ||
import * as asyncHooksModule from 'async_hooks'; | ||
// This file requires async_hooks in the AsyncHooksCLS constructor, rather than | ||
// upon module load. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
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.
LGTM. left some nits.
Intuitively, it didn't make sense how you could implement CLS without the before/after hooks, but after looking at the PR and pondering, I agree with you that this should be correct. As long as we can trust executionAsyncId
to be correct, this code is correct. AsyncWrap does the before/after hooks to ensure that the executionAsyncId is correct. We don't need to. Nice work!
src/cls/async-hooks.ts
Outdated
// constructor, rather than upon module load. | ||
import * as asyncHooksModule from 'async_hooks'; | ||
// This file requires async_hooks in the AsyncHooksCLS constructor, rather than | ||
// upon module load. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
// that runs within the scope of this new AsyncResource to see the same | ||
// context as its "parent" AsyncResource. The criteria for the parent | ||
// depends on the type of the AsyncResource. | ||
if (type === 'PROMISE') { |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
// Getting undefined when looking up this.contexts means that it wasn't | ||
// set, so return the default context. | ||
const current = this.contexts[this.ah.executionAsyncId()]; | ||
return current ? current.value : this.defaultContext; | ||
} | ||
|
||
setContext(value: Context): void { |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
current.value = oldContext; | ||
// Revert the current context to what it was before it was set to the | ||
// captured context. | ||
that.contexts[id] = oldContext; |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
src/cls/async-hooks.ts
Outdated
const boundContext = this.contexts[this.ah.executionAsyncId()]; | ||
// Return if we have already wrapped the function, or there is no current | ||
// context to bind. | ||
if ((fn as ContextWrapped<Func<T>>)[WRAPPED] || !boundContext) { |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This PR introduces the following changes to async_hooks-based tracing:
triggerId
when determining the parentAsyncResource
unless the currentAsyncResource
is of typePROMISE
.this.contexts
upon disabling CLS (in practice, this happens when the Trace Agent is disabled).AsyncResource#runInAsyncScope
, or (2) the function passed to eitherAsyncHooksCLS#runInNewContext
orAsyncHooksCLS#bindToCurrentContext
.this.currentContext
to get the current context, we now directly look up the current context inthis.contexts
based on the current execution ID.before
hook can now be removed.