Skip to content

Commit 00668fc

Browse files
debadree25targos
authored andcommitted
child_process: use signal.reason in child process abort
Fixes: #47814 PR-URL: #47817 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com>
1 parent 9bc5d78 commit 00668fc

4 files changed

+162
-6
lines changed

lib/child_process.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -712,12 +712,12 @@ function normalizeSpawnArguments(file, args, options) {
712712
};
713713
}
714714

715-
function abortChildProcess(child, killSignal) {
715+
function abortChildProcess(child, killSignal, reason) {
716716
if (!child)
717717
return;
718718
try {
719719
if (child.kill(killSignal)) {
720-
child.emit('error', new AbortError());
720+
child.emit('error', new AbortError(undefined, { cause: reason }));
721721
}
722722
} catch (err) {
723723
child.emit('error', err);
@@ -787,7 +787,7 @@ function spawn(file, args, options) {
787787
}
788788

789789
function onAbortListener() {
790-
abortChildProcess(child, killSignal);
790+
abortChildProcess(child, killSignal, options.signal.reason);
791791
}
792792
}
793793

test/parallel/test-child-process-exec-abortcontroller-promisified.js

+45-3
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,36 @@ const waitCommand = common.isWindows ?
1818
const ac = new AbortController();
1919
const signal = ac.signal;
2020
const promise = execPromisifed(waitCommand, { signal });
21-
assert.rejects(promise, /AbortError/, 'post aborted sync signal failed')
22-
.then(common.mustCall());
21+
assert.rejects(promise, {
22+
name: 'AbortError',
23+
cause: new DOMException('This operation was aborted', 'AbortError'),
24+
}).then(common.mustCall());
2325
ac.abort();
2426
}
2527

28+
{
29+
const err = new Error('boom');
30+
const ac = new AbortController();
31+
const signal = ac.signal;
32+
const promise = execPromisifed(waitCommand, { signal });
33+
assert.rejects(promise, {
34+
name: 'AbortError',
35+
cause: err
36+
}).then(common.mustCall());
37+
ac.abort(err);
38+
}
39+
40+
{
41+
const ac = new AbortController();
42+
const signal = ac.signal;
43+
const promise = execPromisifed(waitCommand, { signal });
44+
assert.rejects(promise, {
45+
name: 'AbortError',
46+
cause: 'boom'
47+
}).then(common.mustCall());
48+
ac.abort('boom');
49+
}
50+
2651
{
2752
assert.throws(() => {
2853
execPromisifed(waitCommand, { signal: {} });
@@ -40,6 +65,23 @@ const waitCommand = common.isWindows ?
4065
const signal = AbortSignal.abort(); // Abort in advance
4166
const promise = execPromisifed(waitCommand, { signal });
4267

43-
assert.rejects(promise, /AbortError/, 'pre aborted signal failed')
68+
assert.rejects(promise, { name: 'AbortError' })
69+
.then(common.mustCall());
70+
}
71+
72+
{
73+
const err = new Error('boom');
74+
const signal = AbortSignal.abort(err); // Abort in advance
75+
const promise = execPromisifed(waitCommand, { signal });
76+
77+
assert.rejects(promise, { name: 'AbortError', cause: err })
78+
.then(common.mustCall());
79+
}
80+
81+
{
82+
const signal = AbortSignal.abort('boom'); // Abort in advance
83+
const promise = execPromisifed(waitCommand, { signal });
84+
85+
assert.rejects(promise, { name: 'AbortError', cause: 'boom' })
4486
.then(common.mustCall());
4587
}

test/parallel/test-child-process-fork-abort-signal.js

+37
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,26 @@ const { fork } = require('child_process');
2121
}));
2222
process.nextTick(() => ac.abort());
2323
}
24+
25+
{
26+
// Test aborting with custom error
27+
const ac = new AbortController();
28+
const { signal } = ac;
29+
const cp = fork(fixtures.path('child-process-stay-alive-forever.js'), {
30+
signal
31+
});
32+
cp.on('exit', mustCall((code, killSignal) => {
33+
strictEqual(code, null);
34+
strictEqual(killSignal, 'SIGTERM');
35+
}));
36+
cp.on('error', mustCall((err) => {
37+
strictEqual(err.name, 'AbortError');
38+
strictEqual(err.cause.name, 'Error');
39+
strictEqual(err.cause.message, 'boom');
40+
}));
41+
process.nextTick(() => ac.abort(new Error('boom')));
42+
}
43+
2444
{
2545
// Test passing an already aborted signal to a forked child_process
2646
const signal = AbortSignal.abort();
@@ -36,6 +56,23 @@ const { fork } = require('child_process');
3656
}));
3757
}
3858

59+
{
60+
// Test passing an aborted signal with custom error to a forked child_process
61+
const signal = AbortSignal.abort(new Error('boom'));
62+
const cp = fork(fixtures.path('child-process-stay-alive-forever.js'), {
63+
signal
64+
});
65+
cp.on('exit', mustCall((code, killSignal) => {
66+
strictEqual(code, null);
67+
strictEqual(killSignal, 'SIGTERM');
68+
}));
69+
cp.on('error', mustCall((err) => {
70+
strictEqual(err.name, 'AbortError');
71+
strictEqual(err.cause.name, 'Error');
72+
strictEqual(err.cause.message, 'boom');
73+
}));
74+
}
75+
3976
{
4077
// Test passing a different kill signal
4178
const signal = AbortSignal.abort();

test/parallel/test-child-process-spawn-controller.js

+77
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,48 @@ const aliveScript = fixtures.path('child-process-stay-alive-forever.js');
2727
controller.abort();
2828
}
2929

30+
{
31+
// Verify that passing an AbortSignal with custom abort error works
32+
const controller = new AbortController();
33+
const { signal } = controller;
34+
const cp = spawn(process.execPath, [aliveScript], {
35+
signal,
36+
});
37+
38+
cp.on('exit', common.mustCall((code, killSignal) => {
39+
assert.strictEqual(code, null);
40+
assert.strictEqual(killSignal, 'SIGTERM');
41+
}));
42+
43+
cp.on('error', common.mustCall((e) => {
44+
assert.strictEqual(e.name, 'AbortError');
45+
assert.strictEqual(e.cause.name, 'Error');
46+
assert.strictEqual(e.cause.message, 'boom');
47+
}));
48+
49+
controller.abort(new Error('boom'));
50+
}
51+
52+
{
53+
const controller = new AbortController();
54+
const { signal } = controller;
55+
const cp = spawn(process.execPath, [aliveScript], {
56+
signal,
57+
});
58+
59+
cp.on('exit', common.mustCall((code, killSignal) => {
60+
assert.strictEqual(code, null);
61+
assert.strictEqual(killSignal, 'SIGTERM');
62+
}));
63+
64+
cp.on('error', common.mustCall((e) => {
65+
assert.strictEqual(e.name, 'AbortError');
66+
assert.strictEqual(e.cause, 'boom');
67+
}));
68+
69+
controller.abort('boom');
70+
}
71+
3072
{
3173
// Verify that passing an already-aborted signal works.
3274
const signal = AbortSignal.abort();
@@ -44,6 +86,41 @@ const aliveScript = fixtures.path('child-process-stay-alive-forever.js');
4486
}));
4587
}
4688

89+
{
90+
// Verify that passing an already-aborted signal with custom abort error
91+
// works.
92+
const signal = AbortSignal.abort(new Error('boom'));
93+
const cp = spawn(process.execPath, [aliveScript], {
94+
signal,
95+
});
96+
cp.on('exit', common.mustCall((code, killSignal) => {
97+
assert.strictEqual(code, null);
98+
assert.strictEqual(killSignal, 'SIGTERM');
99+
}));
100+
101+
cp.on('error', common.mustCall((e) => {
102+
assert.strictEqual(e.name, 'AbortError');
103+
assert.strictEqual(e.cause.name, 'Error');
104+
assert.strictEqual(e.cause.message, 'boom');
105+
}));
106+
}
107+
108+
{
109+
const signal = AbortSignal.abort('boom');
110+
const cp = spawn(process.execPath, [aliveScript], {
111+
signal,
112+
});
113+
cp.on('exit', common.mustCall((code, killSignal) => {
114+
assert.strictEqual(code, null);
115+
assert.strictEqual(killSignal, 'SIGTERM');
116+
}));
117+
118+
cp.on('error', common.mustCall((e) => {
119+
assert.strictEqual(e.name, 'AbortError');
120+
assert.strictEqual(e.cause, 'boom');
121+
}));
122+
}
123+
47124
{
48125
// Verify that waiting a bit and closing works
49126
const controller = new AbortController();

0 commit comments

Comments
 (0)