summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/async_hooks.js15
-rw-r--r--test/parallel/test-async-hooks-run-in-async-scope-caught-exception.js9
-rw-r--r--test/parallel/test-emit-after-uncaught-exception-runInAsyncScope.js40
3 files changed, 19 insertions, 45 deletions
diff --git a/lib/async_hooks.js b/lib/async_hooks.js
index 923b9d6758..3ebc9af473 100644
--- a/lib/async_hooks.js
+++ b/lib/async_hooks.js
@@ -22,6 +22,7 @@ const {
executionAsyncId,
triggerAsyncId,
// Private API
+ hasAsyncIdStack,
getHookArrays,
enableHooks,
disableHooks,
@@ -179,12 +180,16 @@ class AsyncResource {
const asyncId = this[async_id_symbol];
emitBefore(asyncId, this[trigger_async_id_symbol], this);
- const ret = thisArg === undefined ?
- fn(...args) :
- ReflectApply(fn, thisArg, args);
+ try {
+ const ret = thisArg === undefined ?
+ fn(...args) :
+ ReflectApply(fn, thisArg, args);
- emitAfter(asyncId);
- return ret;
+ return ret;
+ } finally {
+ if (hasAsyncIdStack())
+ emitAfter(asyncId);
+ }
}
emitDestroy() {
diff --git a/test/parallel/test-async-hooks-run-in-async-scope-caught-exception.js b/test/parallel/test-async-hooks-run-in-async-scope-caught-exception.js
new file mode 100644
index 0000000000..78e38c1e93
--- /dev/null
+++ b/test/parallel/test-async-hooks-run-in-async-scope-caught-exception.js
@@ -0,0 +1,9 @@
+'use strict';
+
+require('../common');
+const { AsyncResource } = require('async_hooks');
+
+try {
+ new AsyncResource('foo').runInAsyncScope(() => { throw new Error('bar'); });
+} catch {}
+// Should abort (fail the case) if async id is not matching.
diff --git a/test/parallel/test-emit-after-uncaught-exception-runInAsyncScope.js b/test/parallel/test-emit-after-uncaught-exception-runInAsyncScope.js
deleted file mode 100644
index 5003972e99..0000000000
--- a/test/parallel/test-emit-after-uncaught-exception-runInAsyncScope.js
+++ /dev/null
@@ -1,40 +0,0 @@
-'use strict';
-
-const common = require('../common');
-const assert = require('assert');
-const async_hooks = require('async_hooks');
-
-const id_obj = {};
-let collect = true;
-
-const hook = async_hooks.createHook({
- before(id) { if (collect) id_obj[id] = true; },
- after(id) { delete id_obj[id]; },
-}).enable();
-
-process.once('uncaughtException', common.mustCall((er) => {
- assert.strictEqual(er.message, 'bye');
- collect = false;
-}));
-
-setImmediate(common.mustCall(() => {
- process.nextTick(common.mustCall(() => {
- assert.strictEqual(Object.keys(id_obj).length, 0);
- hook.disable();
- }));
-
- // Create a stack of async ids that will need to be emitted in the case of
- // an uncaught exception.
- const ar1 = new async_hooks.AsyncResource('Mine');
- ar1.runInAsyncScope(() => {
- const ar2 = new async_hooks.AsyncResource('Mine');
- ar2.runInAsyncScope(() => {
- throw new Error('bye');
- });
- });
-
- // TODO(trevnorris): This test shows that the after() hooks are always called
- // correctly, but it doesn't solve where the emitDestroy() is missed because
- // of the uncaught exception. Simple solution is to always call emitDestroy()
- // before the emitAfter(), but how to codify this?
-}));