From c0b6efc9cbf8fa88398ccc863a8eb554d3a76f93 Mon Sep 17 00:00:00 2001 From: ehmicky <ehmicky@users.noreply.github.com> Date: Wed, 7 Aug 2024 20:29:07 +0100 Subject: [PATCH] Document how to terminate hanging subprocesses (#1140) --- docs/termination.md | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/docs/termination.md b/docs/termination.md index 8c445cd2e2..99ed31da03 100644 --- a/docs/termination.md +++ b/docs/termination.md @@ -124,6 +124,8 @@ If the subprocess is still alive after 5 seconds, it is forcefully terminated wi ## Timeout +### Execution timeout + If the subprocess lasts longer than the [`timeout`](api.md#optionstimeout) option, a [`SIGTERM` signal](#default-signal) is sent to it. ```js @@ -138,6 +140,51 @@ try { } ``` +### Inactivity timeout + +To terminate a subprocess when it becomes inactive, the [`cancelSignal`](#canceling) option can be combined with [transforms](transform.md) and some [debouncing logic](https://github.com/sindresorhus/debounce-fn). The following example terminates the subprocess if it has not printed to [`stdout`](api.md#resultstdout)/[`stderr`](api.md#resultstderr) in the last minute. + +```js +import {execa} from 'execa'; +import debounceFn from 'debounce-fn'; + +// 1 minute +const wait = 60_000; + +const getInactivityOptions = () => { + const controller = new AbortController(); + const cancelSignal = controller.signal; + + // Delay and debounce `cancelSignal` each time `controller.abort()` is called + const scheduleAbort = debounceFn(controller.abort.bind(controller), {wait}); + + const onOutput = { + * transform(data) { + // When anything is printed, debounce `controller.abort()` + scheduleAbort(); + + // Keep the output as is + yield data; + }, + // Debounce even if the output does not include any newline + binary: true, + }; + + // Start debouncing + scheduleAbort(); + + return { + cancelSignal, + stdout: onOutput, + stderr: onOutput, + }; +}; + +const options = getInactivityOptions(); + +await execa(options)`npm run build`; +``` + ## Current process exit If the current process exits, the subprocess is automatically [terminated](#default-signal) unless either: