-
Notifications
You must be signed in to change notification settings - Fork 293
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add scope manager that uses the execution async resource for propagat…
…ion (#1088)
- Loading branch information
Showing
8 changed files
with
224 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
'use strict' | ||
|
||
const { AsyncResource } = require('async_hooks') | ||
|
||
const platform = require('../../packages/dd-trace/src/platform') | ||
const node = require('../../packages/dd-trace/src/platform/node') | ||
const benchmark = require('../benchmark') | ||
|
||
platform.use(node) | ||
|
||
const suite = benchmark('scope (executionAsyncResource)') | ||
|
||
const spanStub = require('../stubs/span') | ||
|
||
const Scope = require('../../packages/dd-trace/src/scope/async_resource') | ||
|
||
const scope = new Scope({ | ||
experimental: {} | ||
}) | ||
|
||
function activateResource (name) { | ||
return scope.activate(spanStub, () => { | ||
return new AsyncResource(name, { | ||
requireManualDestroy: true | ||
}) | ||
}) | ||
} | ||
|
||
suite | ||
.add('Scope#activate', { | ||
fn () { | ||
const resource = activateResource('test') | ||
resource.runInAsyncScope(() => {}) | ||
resource.emitDestroy() | ||
} | ||
}) | ||
.add('Scope#activate (nested)', { | ||
fn () { | ||
const outer = activateResource('outer') | ||
let middle | ||
let inner | ||
|
||
outer.runInAsyncScope(() => { | ||
middle = activateResource('middle') | ||
}) | ||
outer.emitDestroy() | ||
|
||
middle.runInAsyncScope(() => { | ||
inner = activateResource('middle') | ||
}) | ||
middle.emitDestroy() | ||
|
||
inner.runInAsyncScope(() => {}) | ||
inner.emitDestroy() | ||
} | ||
}) | ||
.add('Scope#activate (async)', { | ||
defer: true, | ||
fn (deferred) { | ||
scope.activate(spanStub, () => { | ||
queueMicrotask(() => { | ||
deferred.resolve() | ||
}) | ||
}) | ||
} | ||
}) | ||
.add('Scope#activate (promise)', { | ||
defer: true, | ||
fn (deferred) { | ||
scope.activate(spanStub, () => { | ||
Promise.resolve().then(() => { | ||
deferred.resolve() | ||
}) | ||
}) | ||
} | ||
}) | ||
.add('Scope#activate (async/await)', { | ||
defer: true, | ||
async fn (deferred) { | ||
await scope.activate(spanStub, () => { | ||
return Promise.resolve() | ||
}) | ||
deferred.resolve() | ||
} | ||
}) | ||
.add('Scope#active', { | ||
fn () { | ||
scope.active() | ||
} | ||
}) | ||
|
||
suite.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
'use strict' | ||
|
||
const { createHook, executionAsyncResource } = require('async_hooks') | ||
const Base = require('./base') | ||
|
||
class Scope extends Base { | ||
constructor (config) { | ||
super() | ||
|
||
this._ddResourceStore = Symbol('ddResourceStore') | ||
this._config = config | ||
this._stack = [] | ||
this._hook = createHook({ | ||
init: this._init.bind(this) | ||
}) | ||
|
||
this.enable() | ||
} | ||
|
||
enable () { | ||
this._enabled = true | ||
this._hook.enable() | ||
} | ||
|
||
disable () { | ||
this._enabled = false | ||
this._stack = [] | ||
this._hook.disable() | ||
} | ||
|
||
_active () { | ||
if (!this._enabled) return null | ||
|
||
const resource = executionAsyncResource() | ||
|
||
return resource[this._ddResourceStore] || null | ||
} | ||
|
||
_activate (span, callback) { | ||
if (!this._enabled) return callback() | ||
|
||
const resource = executionAsyncResource() | ||
|
||
this._enter(span, resource) | ||
|
||
try { | ||
return callback() | ||
} finally { | ||
this._exit(resource) | ||
} | ||
} | ||
|
||
_enter (span, resource) { | ||
this._stack.push(resource[this._ddResourceStore]) | ||
resource[this._ddResourceStore] = span | ||
} | ||
|
||
_exit (resource) { | ||
resource[this._ddResourceStore] = this._stack.pop() | ||
} | ||
|
||
_init (asyncId, type, triggerAsyncId, resource) { | ||
const triggerResource = executionAsyncResource() | ||
const span = triggerResource[this._ddResourceStore] | ||
|
||
if (span) { | ||
resource[this._ddResourceStore] = span | ||
} | ||
} | ||
} | ||
|
||
module.exports = Scope |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
'use strict' | ||
|
||
const { | ||
AsyncResource, | ||
executionAsyncId | ||
} = require('async_hooks') | ||
const Scope = require('../../src/scope/async_resource') | ||
const Span = require('opentracing').Span | ||
const semver = require('semver') | ||
const testScope = require('./test') | ||
|
||
wrapIt('async_resource') | ||
|
||
// https:// nodejs.org/api/async_hooks.html#async_hooks_async_hooks_executionasyncresource | ||
if (semver.satisfies(process.version, '^12.17.0 || >=13.9.0')) { | ||
describe('Scope (executionAsyncResource)', test) | ||
} else { | ||
describe.skip('Scope (executionAsyncResource)', test) | ||
} | ||
|
||
function test () { | ||
let scope | ||
let span | ||
|
||
beforeEach(() => { | ||
scope = new Scope() | ||
span = new Span() | ||
}) | ||
|
||
afterEach(() => { | ||
scope.disable() | ||
}) | ||
|
||
it('should not break propagation for nested resources', () => { | ||
scope.activate(span, () => { | ||
const asyncResource = new AsyncResource( | ||
'TEST', { triggerAsyncId: executionAsyncId(), requireManualDestroy: false } | ||
) | ||
|
||
asyncResource.runInAsyncScope(() => {}) | ||
|
||
expect(scope.active()).to.equal(span) | ||
}) | ||
}) | ||
|
||
testScope(() => scope) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters