Skip to content
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

async_hooks: use parent promise as triggerId in init hook #13367

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/async-wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,23 @@ static void PromiseHook(PromiseHookType type, Local<Promise> promise,
PromiseWrap* wrap = Unwrap<PromiseWrap>(promise);
if (type == PromiseHookType::kInit || wrap == nullptr) {
bool silent = type != PromiseHookType::kInit;
// set parent promise's async Id as this promise's triggerId
if (parent->IsPromise()) {
// parent promise exists, current promise
// is a chained promise, so we set parent promise's id as
// current promise's triggerId
Local<Promise> parent_promise = parent.As<Promise>();
auto parent_wrap = Unwrap<PromiseWrap>(parent_promise);

if (parent_wrap == nullptr) {
// create a new PromiseWrap for parent promise with silent parameter
parent_wrap = new PromiseWrap(env, parent_promise, true);
parent_wrap->MakeWeak(parent_wrap);
}
// get id from parentWrap
double trigger_id = parent_wrap->get_id();
env->set_init_trigger_id(trigger_id);
}
wrap = new PromiseWrap(env, promise, silent);
wrap->MakeWeak(wrap);
} else if (type == PromiseHookType::kResolve) {
Expand Down
41 changes: 41 additions & 0 deletions test/async-hooks/test-promise.chain-promise-before-init-hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';

const common = require('../common');
const assert = require('assert');
const initHooks = require('./init-hooks');
const { checkInvocations } = require('./hook-checks');

const p = (new Promise(common.mustCall(executor)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don’t need the outer parentheses here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I will remove it.

p.then(afterresolution);

// init hooks after chained promise is created
const hooks = initHooks();
hooks._allowNoInit = true;
hooks.enable();

function executor(resolve, reject) {
resolve(5);
}

function afterresolution(val) {
assert.strictEqual(val, 5);
return val;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would be a bit more readable if you just inlined executor and afterresolution

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, you are right, I will change it.


process.on('exit', onexit);
function onexit() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same for onexit, using process.on('exit', () => { works just fine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I will change it.

hooks.disable();
hooks.sanityCheck('PROMISE');

const as = hooks.activitiesOfTypes('PROMISE');
const unknown = hooks.activitiesOfTypes('Unknown');
assert.strictEqual(as.length, 0, 'no activities with PROMISE type');
assert.strictEqual(unknown.length, 1,
'one activity with Unknown type which in fact is PROMISE');

const a0 = unknown[0];
assert.strictEqual(a0.type, 'Unknown',
'unknown request which in fact is PROMISE');
assert.strictEqual(typeof a0.uid, 'number', 'uid is a number');
checkInvocations(a0, { before: 1, after: 1 }, 'when process exits');
}
5 changes: 3 additions & 2 deletions test/async-hooks/test-promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ p.then(afterresolution);

function executor(resolve, reject) {
const as = hooks.activitiesOfTypes('PROMISE');
assert.strictEqual(as.length, 1, 'one activities');
assert.strictEqual(as.length, 1, 'one activity');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to avoid merge conflicts with #13243, you can just drop this change

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@addaleax , ok , so I just revert it.

const a = as[0];
checkInvocations(a, { init: 1 }, 'while in promise executor');
resolve(5);
Expand Down Expand Up @@ -46,7 +46,8 @@ function onexit() {
const a1 = as[1];
assert.strictEqual(a1.type, 'PROMISE', 'promise request');
assert.strictEqual(typeof a1.uid, 'number', 'uid is a number');
assert.strictEqual(a1.triggerId, 1, 'parent uid 1');
assert.strictEqual(a1.triggerId, a0.uid,
'child promise should use parent uid as triggerId');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I would just not use an error message here (i.e. assert.strictEqual(a1.triggerId, a0.uid);). Sorry the tests are written this way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, so I just modify it to

assert.strictEqual(a1.triggerId, a0.uid);

// We expect a destroy hook as well but we cannot guarentee predictable gc.
checkInvocations(a1, { init: 1, before: 1, after: 1 }, 'when process exits');
}
47 changes: 47 additions & 0 deletions test/async-hooks/test-promise.promise-before-init-hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';

const common = require('../common');
const assert = require('assert');
const initHooks = require('./init-hooks');
const { checkInvocations } = require('./hook-checks');

const p = (new Promise(common.mustCall(executor)));

// init hooks after promise was created
const hooks = initHooks();
hooks._allowNoInit = true;
hooks.enable();

p.then(afterresolution);

function executor(resolve, reject) {
resolve(5);
}

function afterresolution(val) {
assert.strictEqual(val, 5);
const as = hooks.activitiesOfTypes('PROMISE');
assert.strictEqual(as.length, 1, 'one activity');
checkInvocations(as[0], { init: 1, before: 1 },
'after resolution child promise');
return val;
}

process.on('exit', onexit);
function onexit() {
hooks.disable();
hooks.sanityCheck('PROMISE');

const as = hooks.activitiesOfTypes('PROMISE');
assert.strictEqual(as.length, 1,
'should only get one activity(child promise)');

const a0 = as[0];
assert.strictEqual(a0.type, 'PROMISE', 'promise request');
assert.strictEqual(typeof a0.uid, 'number', 'uid is a number');
// we can't get the triggerId dynamically, we have to use static number here
assert.strictEqual(a0.triggerId - (a0.uid - 3), 2,
'child promise should use parent uid as triggerId');
// We expect a destroy hook as well but we cannot guarentee predictable gc.
checkInvocations(a0, { init: 1, before: 1, after: 1 }, 'when process exits');
}