Skip to content

Commit 9d06443

Browse files
committed
async_hooks: remove deprecated emitBefore and emitAfter
AsyncResource.emitBefore and AsyncResource.emitAfter have been deprecated in #18632. This PR removes it all. This commit also updates some embedder tests to use internal APIs. The conditions are still possible for Node.js core developers but not for end users. PR-URL: #26530 Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ali Ijaz Sheikh <[email protected]> Reviewed-By: Benedikt Meurer <[email protected]> Reviewed-By: Yang Guo <[email protected]> Reviewed-By: Andreas Madsen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent abafd38 commit 9d06443

11 files changed

+130
-133
lines changed

doc/api/async_hooks.md

-36
Original file line numberDiff line numberDiff line change
@@ -659,41 +659,6 @@ of the async resource. This will establish the context, trigger the AsyncHooks
659659
before callbacks, call the function, trigger the AsyncHooks after callbacks, and
660660
then restore the original execution context.
661661

662-
#### asyncResource.emitBefore()
663-
<!-- YAML
664-
deprecated: v9.6.0
665-
-->
666-
> Stability: 0 - Deprecated: Use [`asyncResource.runInAsyncScope()`][] instead.
667-
668-
Call all `before` callbacks to notify that a new asynchronous execution context
669-
is being entered. If nested calls to `emitBefore()` are made, the stack of
670-
`asyncId`s will be tracked and properly unwound.
671-
672-
`before` and `after` calls must be unwound in the same order that they
673-
are called. Otherwise, an unrecoverable exception will occur and the process
674-
will abort. For this reason, the `emitBefore` and `emitAfter` APIs are
675-
considered deprecated. Please use `runInAsyncScope`, as it provides a much safer
676-
alternative.
677-
678-
#### asyncResource.emitAfter()
679-
<!-- YAML
680-
deprecated: v9.6.0
681-
-->
682-
> Stability: 0 - Deprecated: Use [`asyncResource.runInAsyncScope()`][] instead.
683-
684-
Call all `after` callbacks. If nested calls to `emitBefore()` were made, then
685-
make sure the stack is unwound properly. Otherwise an error will be thrown.
686-
687-
If the user's callback throws an exception, `emitAfter()` will automatically be
688-
called for all `asyncId`s on the stack if the error is handled by a domain or
689-
`'uncaughtException'` handler.
690-
691-
`before` and `after` calls must be unwound in the same order that they
692-
are called. Otherwise, an unrecoverable exception will occur and the process
693-
will abort. For this reason, the `emitBefore` and `emitAfter` APIs are
694-
considered deprecated. Please use `runInAsyncScope`, as it provides a much safer
695-
alternative.
696-
697662
#### asyncResource.emitDestroy()
698663

699664
* Returns: {AsyncResource} A reference to `asyncResource`.
@@ -713,7 +678,6 @@ never be called.
713678
`AsyncResource` constructor.
714679

715680
[`after` callback]: #async_hooks_after_asyncid
716-
[`asyncResource.runInAsyncScope()`]: #async_hooks_asyncresource_runinasyncscope_fn_thisarg_args
717681
[`before` callback]: #async_hooks_before_asyncid
718682
[`destroy` callback]: #async_hooks_destroy_asyncid
719683
[`init` callback]: #async_hooks_init_asyncid_type_triggerasyncid_resource

doc/api/deprecations.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -1905,6 +1905,9 @@ should start using the `async_context` variant of `MakeCallback` or
19051905
### DEP0098: AsyncHooks Embedder AsyncResource.emitBefore and AsyncResource.emitAfter APIs
19061906
<!-- YAML
19071907
changes:
1908+
- version: REPLACEME
1909+
pr-url:
1910+
description: End-of-Life
19081911
- version:
19091912
- v8.12.0
19101913
- v9.6.0
@@ -1913,7 +1916,7 @@ changes:
19131916
description: Runtime deprecation.
19141917
-->
19151918
1916-
Type: Runtime
1919+
Type: End-of-Life
19171920
19181921
The embedded API provided by AsyncHooks exposes `.emitBefore()` and
19191922
`.emitAfter()` methods which are very easy to use incorrectly which can lead

lib/async_hooks.js

-23
Original file line numberDiff line numberDiff line change
@@ -127,17 +127,6 @@ function createHook(fns) {
127127

128128
const destroyedSymbol = Symbol('destroyed');
129129

130-
let emitBeforeAfterWarning = true;
131-
function showEmitBeforeAfterWarning() {
132-
if (emitBeforeAfterWarning) {
133-
process.emitWarning(
134-
'asyncResource.emitBefore and emitAfter are deprecated. Please use ' +
135-
'asyncResource.runInAsyncScope instead',
136-
'DeprecationWarning', 'DEP0098');
137-
emitBeforeAfterWarning = false;
138-
}
139-
}
140-
141130
class AsyncResource {
142131
constructor(type, opts = {}) {
143132
validateString(type, 'type');
@@ -169,18 +158,6 @@ class AsyncResource {
169158
}
170159
}
171160

172-
emitBefore() {
173-
showEmitBeforeAfterWarning();
174-
emitBefore(this[async_id_symbol], this[trigger_async_id_symbol]);
175-
return this;
176-
}
177-
178-
emitAfter() {
179-
showEmitBeforeAfterWarning();
180-
emitAfter(this[async_id_symbol]);
181-
return this;
182-
}
183-
184161
runInAsyncScope(fn, thisArg, ...args) {
185162
emitBefore(this[async_id_symbol], this[trigger_async_id_symbol]);
186163
let ret;

test/async-hooks/test-callback-error.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ switch (arg) {
1919
onbefore: common.mustCall(() => { throw new Error(arg); })
2020
}).enable();
2121
const resource = new async_hooks.AsyncResource(`${arg}_type`);
22-
resource.emitBefore();
22+
resource.runInAsyncScope(() => {});
2323
return;
2424

2525
case 'test_callback_abort':

test/async-hooks/test-embedder.api.async-resource.js

+12-12
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,16 @@ assert.strictEqual(typeof alcaEvent.asyncId(), 'number');
4747
assert.notStrictEqual(alcaEvent.asyncId(), alcaTriggerId);
4848
assert.strictEqual(alcaEvent.triggerAsyncId(), alcaTriggerId);
4949

50-
alcaEvent.emitBefore();
51-
checkInvocations(alcazares, { init: 1, before: 1 },
52-
'alcazares emitted before');
53-
alcaEvent.emitAfter();
50+
alcaEvent.runInAsyncScope(() => {
51+
checkInvocations(alcazares, { init: 1, before: 1 },
52+
'alcazares emitted before');
53+
});
5454
checkInvocations(alcazares, { init: 1, before: 1, after: 1 },
5555
'alcazares emitted after');
56-
alcaEvent.emitBefore();
57-
checkInvocations(alcazares, { init: 1, before: 2, after: 1 },
58-
'alcazares emitted before again');
59-
alcaEvent.emitAfter();
56+
alcaEvent.runInAsyncScope(() => {
57+
checkInvocations(alcazares, { init: 1, before: 2, after: 1 },
58+
'alcazares emitted before again');
59+
});
6060
checkInvocations(alcazares, { init: 1, before: 2, after: 2 },
6161
'alcazares emitted after again');
6262
alcaEvent.emitDestroy();
@@ -75,11 +75,11 @@ function tick1() {
7575
assert.strictEqual(typeof poblado.uid, 'number');
7676
assert.strictEqual(poblado.triggerAsyncId, pobTriggerId);
7777
checkInvocations(poblado, { init: 1 }, 'poblado constructed');
78-
pobEvent.emitBefore();
79-
checkInvocations(poblado, { init: 1, before: 1 },
80-
'poblado emitted before');
78+
pobEvent.runInAsyncScope(() => {
79+
checkInvocations(poblado, { init: 1, before: 1 },
80+
'poblado emitted before');
81+
});
8182

82-
pobEvent.emitAfter();
8383
checkInvocations(poblado, { init: 1, before: 1, after: 1 },
8484
'poblado emitted after');
8585

test/async-hooks/test-embedder.api.async-resource.after-on-destroyed.js test/async-hooks/test-emit-after-on-destroyed.js

+26-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1+
// Flags: --expose-internals
12
'use strict';
23

34
const common = require('../common');
45
const assert = require('assert');
5-
const async_hooks = require('async_hooks');
6-
const { AsyncResource } = async_hooks;
6+
const internal_async_hooks = require('internal/async_hooks');
77
const { spawn } = require('child_process');
88
const corruptedMsg = /async hook stack has become corrupted/;
99
const heartbeatMsg = /heartbeat: still alive/;
1010

11+
const {
12+
newAsyncId, getDefaultTriggerAsyncId,
13+
emitInit, emitBefore, emitAfter, emitDestroy
14+
} = internal_async_hooks;
15+
1116
const initHooks = require('./init-hooks');
1217

1318
if (process.argv[2] === 'child') {
@@ -17,20 +22,29 @@ if (process.argv[2] === 'child') {
1722
// Once 'destroy' has been emitted, we can no longer emit 'after'
1823

1924
// Emitting 'before', 'after' and then 'destroy'
20-
const event1 = new AsyncResource('event1', async_hooks.executionAsyncId());
21-
event1.emitBefore();
22-
event1.emitAfter();
23-
event1.emitDestroy();
25+
{
26+
const asyncId = newAsyncId();
27+
const triggerId = getDefaultTriggerAsyncId();
28+
emitInit(asyncId, 'event1', triggerId, {});
29+
emitBefore(asyncId, triggerId);
30+
emitAfter(asyncId);
31+
emitDestroy(asyncId);
32+
}
2433

2534
// Emitting 'after' after 'destroy'
26-
const event2 = new AsyncResource('event2', async_hooks.executionAsyncId());
27-
event2.emitDestroy();
28-
29-
console.log('heartbeat: still alive');
30-
event2.emitAfter();
35+
{
36+
const asyncId = newAsyncId();
37+
const triggerId = getDefaultTriggerAsyncId();
38+
emitInit(asyncId, 'event2', triggerId, {});
39+
emitDestroy(asyncId);
3140

41+
console.log('heartbeat: still alive');
42+
emitAfter(asyncId);
43+
}
3244
} else {
33-
const args = process.argv.slice(1).concat('child');
45+
const args = ['--expose-internals']
46+
.concat(process.argv.slice(1))
47+
.concat('child');
3448
let errData = Buffer.from('');
3549
let outData = Buffer.from('');
3650

test/async-hooks/test-embedder.api.async-resource.before-on-destroyed.js test/async-hooks/test-emit-before-on-destroyed.js

+26-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1+
// Flags: --expose-internals
12
'use strict';
23

34
const common = require('../common');
45
const assert = require('assert');
5-
const async_hooks = require('async_hooks');
6-
const { AsyncResource } = async_hooks;
6+
const internal_async_hooks = require('internal/async_hooks');
77
const { spawn } = require('child_process');
88
const corruptedMsg = /async hook stack has become corrupted/;
99
const heartbeatMsg = /heartbeat: still alive/;
1010

11+
const {
12+
newAsyncId, getDefaultTriggerAsyncId,
13+
emitInit, emitBefore, emitAfter, emitDestroy
14+
} = internal_async_hooks;
15+
1116
const initHooks = require('./init-hooks');
1217

1318
if (process.argv[2] === 'child') {
@@ -17,20 +22,29 @@ if (process.argv[2] === 'child') {
1722
// Once 'destroy' has been emitted, we can no longer emit 'before'
1823

1924
// Emitting 'before', 'after' and then 'destroy'
20-
const event1 = new AsyncResource('event1', async_hooks.executionAsyncId());
21-
event1.emitBefore();
22-
event1.emitAfter();
23-
event1.emitDestroy();
25+
{
26+
const asyncId = newAsyncId();
27+
const triggerId = getDefaultTriggerAsyncId();
28+
emitInit(asyncId, 'event1', triggerId, {});
29+
emitBefore(asyncId, triggerId);
30+
emitAfter(asyncId);
31+
emitDestroy(asyncId);
32+
}
2433

2534
// Emitting 'before' after 'destroy'
26-
const event2 = new AsyncResource('event2', async_hooks.executionAsyncId());
27-
event2.emitDestroy();
28-
29-
console.log('heartbeat: still alive');
30-
event2.emitBefore();
35+
{
36+
const asyncId = newAsyncId();
37+
const triggerId = getDefaultTriggerAsyncId();
38+
emitInit(asyncId, 'event2', triggerId, {});
39+
emitDestroy(asyncId);
3140

41+
console.log('heartbeat: still alive');
42+
emitBefore(asyncId, triggerId);
43+
}
3244
} else {
33-
const args = process.argv.slice(1).concat('child');
45+
const args = ['--expose-internals']
46+
.concat(process.argv.slice(1))
47+
.concat('child');
3448
let errData = Buffer.from('');
3549
let outData = Buffer.from('');
3650

test/async-hooks/test-embedder.api.async-resource.improper-order.js test/async-hooks/test-improper-order.js

+25-10
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1+
// Flags: --expose-internals
12
'use strict';
23

34
const common = require('../common');
45
const assert = require('assert');
5-
const async_hooks = require('async_hooks');
6-
const { AsyncResource } = async_hooks;
6+
const internal_async_hooks = require('internal/async_hooks');
77
const { spawn } = require('child_process');
88
const corruptedMsg = /async hook stack has become corrupted/;
99
const heartbeatMsg = /heartbeat: still alive/;
1010

11+
const {
12+
newAsyncId, getDefaultTriggerAsyncId,
13+
emitInit, emitBefore, emitAfter
14+
} = internal_async_hooks;
15+
1116
const initHooks = require('./init-hooks');
1217

1318
if (process.argv[2] === 'child') {
@@ -17,18 +22,28 @@ if (process.argv[2] === 'child') {
1722
// Async hooks enforce proper order of 'before' and 'after' invocations
1823

1924
// Proper ordering
20-
const event1 = new AsyncResource('event1', async_hooks.executionAsyncId());
21-
event1.emitBefore();
22-
event1.emitAfter();
25+
{
26+
const asyncId = newAsyncId();
27+
const triggerId = getDefaultTriggerAsyncId();
28+
emitInit(asyncId, 'event1', triggerId, {});
29+
emitBefore(asyncId, triggerId);
30+
emitAfter(asyncId);
31+
}
2332

2433
// Improper ordering
2534
// Emitting 'after' without 'before' which is illegal
26-
const event2 = new AsyncResource('event2', async_hooks.executionAsyncId());
27-
28-
console.log('heartbeat: still alive');
29-
event2.emitAfter();
35+
{
36+
const asyncId = newAsyncId();
37+
const triggerId = getDefaultTriggerAsyncId();
38+
emitInit(asyncId, 'event2', triggerId, {});
39+
40+
console.log('heartbeat: still alive');
41+
emitAfter(asyncId);
42+
}
3043
} else {
31-
const args = process.argv.slice(1).concat('child');
44+
const args = ['--expose-internals']
45+
.concat(process.argv.slice(1))
46+
.concat('child');
3247
let errData = Buffer.from('');
3348
let outData = Buffer.from('');
3449

test/async-hooks/test-embedder.api.async-resource.improper-unwind.js test/async-hooks/test-improper-unwind.js

+22-12
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
1+
// Flags: --expose-internals
12
'use strict';
23

34
const common = require('../common');
45
const assert = require('assert');
5-
const async_hooks = require('async_hooks');
6-
const { AsyncResource } = async_hooks;
6+
const internal_async_hooks = require('internal/async_hooks');
77
const { spawn } = require('child_process');
88
const corruptedMsg = /async hook stack has become corrupted/;
99
const heartbeatMsg = /heartbeat: still alive/;
1010

11+
const {
12+
newAsyncId, getDefaultTriggerAsyncId,
13+
emitInit, emitBefore, emitAfter
14+
} = internal_async_hooks;
15+
1116
const initHooks = require('./init-hooks');
1217

1318
if (process.argv[2] === 'child') {
@@ -21,23 +26,28 @@ if (process.argv[2] === 'child') {
2126
// The first test of the two below follows that rule,
2227
// the second one doesn't.
2328

24-
const event1 = new AsyncResource('event1', async_hooks.executionAsyncId());
25-
const event2 = new AsyncResource('event2', async_hooks.executionAsyncId());
29+
const eventOneId = newAsyncId();
30+
const eventTwoId = newAsyncId();
31+
const triggerId = getDefaultTriggerAsyncId();
32+
emitInit(eventOneId, 'event1', triggerId, {});
33+
emitInit(eventTwoId, 'event2', triggerId, {});
2634

2735
// Proper unwind
28-
event1.emitBefore();
29-
event2.emitBefore();
30-
event2.emitAfter();
31-
event1.emitAfter();
36+
emitBefore(eventOneId, triggerId);
37+
emitBefore(eventTwoId, triggerId);
38+
emitAfter(eventTwoId);
39+
emitAfter(eventOneId);
3240

3341
// Improper unwind
34-
event1.emitBefore();
35-
event2.emitBefore();
42+
emitBefore(eventOneId, triggerId);
43+
emitBefore(eventTwoId, triggerId);
3644

3745
console.log('heartbeat: still alive');
38-
event1.emitAfter();
46+
emitAfter(eventOneId);
3947
} else {
40-
const args = process.argv.slice(1).concat('child');
48+
const args = ['--expose-internals']
49+
.concat(process.argv.slice(1))
50+
.concat('child');
4151
let errData = Buffer.from('');
4252
let outData = Buffer.from('');
4353

0 commit comments

Comments
 (0)