diff options
author | Leo Kettmeir <crowlkats@toaxl.com> | 2022-05-11 07:59:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-11 07:59:39 +0200 |
commit | b67f874b3fb172168997be410b1d5e3c3109c763 (patch) | |
tree | ab24a5ffe1fd7bb54a43e9a6b3e4b13fa153cfe7 | |
parent | e3f4b02f48c1e1b1e70cb9237126b9bc5d9720e3 (diff) |
feat(runtime/spawn): add `AbortSignal` support (#14538)
-rw-r--r-- | cli/dts/lib.deno.unstable.d.ts | 6 | ||||
-rw-r--r-- | cli/tests/unit/spawn_test.ts (renamed from cli/tests/unit/command_test.ts) | 26 | ||||
-rw-r--r-- | runtime/js/40_spawn.js | 12 |
3 files changed, 43 insertions, 1 deletions
diff --git a/cli/dts/lib.deno.unstable.d.ts b/cli/dts/lib.deno.unstable.d.ts index fbbe165f9..ca437bf44 100644 --- a/cli/dts/lib.deno.unstable.d.ts +++ b/cli/dts/lib.deno.unstable.d.ts @@ -1346,6 +1346,12 @@ declare namespace Deno { uid?: number; /** Similar to `uid`, but sets the group ID of the child process. */ gid?: number; + /** + * An AbortSignal that allows closing the process using the corresponding + * AbortController by sending the process a SIGTERM signal. + * Not Supported by execSync. + */ + signal?: AbortSignal; /** Defaults to "null". */ stdin?: "piped" | "inherit" | "null"; diff --git a/cli/tests/unit/command_test.ts b/cli/tests/unit/spawn_test.ts index 4b3d5bd11..c2c7fdbac 100644 --- a/cli/tests/unit/command_test.ts +++ b/cli/tests/unit/spawn_test.ts @@ -249,6 +249,32 @@ Deno.test( ); Deno.test( + { permissions: { run: true, read: true } }, + async function spawnAbort() { + const ac = new AbortController(); + const child = Deno.spawnChild(Deno.execPath(), { + args: [ + "eval", + "setTimeout(console.log, 1e8)", + ], + signal: ac.signal, + stdout: "null", + stderr: "null", + }); + queueMicrotask(() => ac.abort()); + const status = await child.status; + assertEquals(status.success, false); + if (Deno.build.os === "windows") { + assertEquals(status.code, 1); + assertEquals(status.signal, null); + } else { + assertEquals(status.success, false); + assertEquals(status.code, 143); + } + }, +); + +Deno.test( { permissions: { read: true, run: false } }, async function spawnPermissions() { await assertRejects(async () => { diff --git a/runtime/js/40_spawn.js b/runtime/js/40_spawn.js index 3b609be8b..4f680c7e1 100644 --- a/runtime/js/40_spawn.js +++ b/runtime/js/40_spawn.js @@ -5,6 +5,7 @@ const core = window.Deno.core; const { pathFromURL } = window.__bootstrap.util; const { illegalConstructorKey } = window.__bootstrap.webUtil; + const { add, remove } = window.__bootstrap.abortSignal; const { ArrayPrototypeMap, ObjectEntries, @@ -26,6 +27,7 @@ stdin = "null", stdout = "piped", stderr = "piped", + signal = undefined, } = {}) { const child = core.opSync("op_spawn_child", { cmd: pathFromURL(command), @@ -39,7 +41,10 @@ stdout, stderr, }); - return new Child(illegalConstructorKey, child); + return new Child(illegalConstructorKey, { + ...child, + signal, + }); } async function collectOutput(readableStream) { @@ -91,6 +96,7 @@ } constructor(key = null, { + signal, rid, pid, stdinRid, @@ -119,8 +125,12 @@ this.#stderr = readableStreamForRid(stderrRid); } + const onAbort = () => this.kill("SIGTERM"); + signal?.[add](onAbort); + this.#status = core.opAsync("op_spawn_wait", this.#rid).then((res) => { this.#rid = null; + signal?.[remove](onAbort); return res; }); } |