GeezerVison is showing github.com — child_process: use signal.reason in child process abort · nodejs/node@00668fc
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/child_process.js +3-3Lines changed: 3 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -712,12 +712,12 @@ function normalizeSpawnArguments(file, args, options) { | 712 | 712 | }; | 713 | 713 | } | 714 | 714 |
| 715 | | -function abortChildProcess(child, killSignal) { | | 715 | +function abortChildProcess(child, killSignal, reason) { | 716 | 716 | if (!child) | 717 | 717 | return; | 718 | 718 | try { | 719 | 719 | if (child.kill(killSignal)) { | 720 | | - child.emit('error', new AbortError()); | | 720 | + child.emit('error', new AbortError(undefined, { cause: reason })); | 721 | 721 | } | 722 | 722 | } catch (err) { | 723 | 723 | child.emit('error', err); | @@ -787,7 +787,7 @@ function spawn(file, args, options) { | 787 | 787 | } | 788 | 788 |
| 789 | 789 | function onAbortListener() { | 790 | | - abortChildProcess(child, killSignal); | | 790 | + abortChildProcess(child, killSignal, options.signal.reason); | 791 | 791 | } | 792 | 792 | } | 793 | 793 |
| |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-child-process-exec-abortcontroller-promisified.js +45-3Lines changed: 45 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -18,11 +18,36 @@ const waitCommand = common.isWindows ? | 18 | 18 | const ac = new AbortController(); | 19 | 19 | const signal = ac.signal; | 20 | 20 | 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()); | 23 | 25 | ac.abort(); | 24 | 26 | } | 25 | 27 |
| | 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 | + | 26 | 51 | { | 27 | 52 | assert.throws(() => { | 28 | 53 | execPromisifed(waitCommand, { signal: {} }); | @@ -40,6 +65,23 @@ const waitCommand = common.isWindows ? | 40 | 65 | const signal = AbortSignal.abort(); // Abort in advance | 41 | 66 | const promise = execPromisifed(waitCommand, { signal }); | 42 | 67 |
| 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' }) | 44 | 86 | .then(common.mustCall()); | 45 | 87 | } |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-child-process-fork-abort-signal.js +37Lines changed: 37 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -21,6 +21,26 @@ const { fork } = require('child_process'); | 21 | 21 | })); | 22 | 22 | process.nextTick(() => ac.abort()); | 23 | 23 | } | | 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 | + | 24 | 44 | { | 25 | 45 | // Test passing an already aborted signal to a forked child_process | 26 | 46 | const signal = AbortSignal.abort(); | @@ -36,6 +56,23 @@ const { fork } = require('child_process'); | 36 | 56 | })); | 37 | 57 | } | 38 | 58 |
| | 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 | + | 39 | 76 | { | 40 | 77 | // Test passing a different kill signal | 41 | 78 | const signal = AbortSignal.abort(); | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-child-process-spawn-controller.js +77Lines changed: 77 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -27,6 +27,48 @@ const aliveScript = fixtures.path('child-process-stay-alive-forever.js'); | 27 | 27 | controller.abort(); | 28 | 28 | } | 29 | 29 |
| | 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 | + | 30 | 72 | { | 31 | 73 | // Verify that passing an already-aborted signal works. | 32 | 74 | const signal = AbortSignal.abort(); | @@ -44,6 +86,41 @@ const aliveScript = fixtures.path('child-process-stay-alive-forever.js'); | 44 | 86 | })); | 45 | 87 | } | 46 | 88 |
| | 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 | + | 47 | 124 | { | 48 | 125 | // Verify that waiting a bit and closing works | 49 | 126 | const controller = new AbortController(); | |
|