Files
node/test/parallel/test-domain-error-handler-throw-no-recursion.js
T
Matteo Collina 2c4356cedf domain: port to AsyncLocalStorage
Port the domain module from createHook (async_hooks) to
AsyncLocalStorage using the AsyncContextFrame-based implementation.

Key changes:
- Use AsyncLocalStorage for domain context propagation instead of
  async_hooks.createHook()
- Lazy initialization that triggers AsyncContextFrame prototype swap
  on first domain use
- Use enterWith instead of ALS.run() so domain context is NOT
  automatically restored on exception - this matches the original
  domain.run() behavior where exit() only runs on success
- Add ERR_ASYNC_RESOURCE_DOMAIN_REMOVED error for AsyncResource.domain
- Update DEP0097 to End-of-Life status
- Remove tests that relied on the removed MakeCallback domain property

The domain module now uses the AsyncContextFrame version of
AsyncLocalStorage directly for proper context propagation across
async boundaries.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/61095
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
2026-06-21 19:42:03 +00:00

46 lines
1.4 KiB
JavaScript

'use strict';
const common = require('../common');
const assert = require('assert');
const domain = require('domain');
// Test that when a domain's error handler throws, the exception does NOT
// recursively call the same domain's error handler. Instead, it should
// propagate to the parent domain or crash the process.
let d1ErrorCount = 0;
let d2ErrorCount = 0;
const d1 = domain.create();
const d2 = domain.create();
d1.on('error', common.mustCall((err) => {
d1ErrorCount++;
assert.strictEqual(err.message, 'from d2 error handler');
// d1 should only be called once - when d2's error handler throws
assert.strictEqual(d1ErrorCount, 1);
}));
d2.on('error', common.mustCall((err) => {
d2ErrorCount++;
// d2's error handler should only be called once for the original error
assert.strictEqual(d2ErrorCount, 1);
assert.strictEqual(err.message, 'original error');
// Throwing here should go to d1, NOT back to d2
throw new Error('from d2 error handler');
}));
d1.run(() => {
d2.run(() => {
// Emit an error on an EventEmitter bound to d2
const EventEmitter = require('events');
const ee = new EventEmitter();
d2.add(ee);
// This should:
// 1. Call d2's error handler with 'original error'
// 2. d2's error handler throws 'from d2 error handler'
// 3. That exception should go to d1's error handler, NOT d2 again
ee.emit('error', new Error('original error'));
});
});