@zukhruf/shutdown 0.0.0-stage → 0.6.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ezzabuzaid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,170 @@
1
- # Temporary Holding Version
1
+ # @zukhruf/shutdown
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A graceful shutdown for a Node.js program. When the user presses Ctrl-C, or Docker stops the container, the program does not end at once. Its work stops when the signal aborts, its cleanup runs, and then the process ends by the same termination signal. Thus the shell, Docker or Kubernetes sees an interrupted process, not a process that completed its work. The package has no dependencies.
4
+
5
+ The words in these documents have one meaning each. See the glossary in [CONTEXT.md](./CONTEXT.md).
6
+
7
+ ## Stop the work at a termination signal
8
+
9
+ Make one `Shutdown` at the start of the entry point, before the first `await`. Then a termination signal during the start also stops the work. Give the signal to the work:
10
+
11
+ ```ts
12
+ import { Shutdown } from '@zukhruf/shutdown';
13
+
14
+ using shutdown = new Shutdown();
15
+ using warehouse = new Warehouse('credits.sqlite');
16
+ await pipeline.run({ signal: shutdown.signal });
17
+ ```
18
+
19
+ The user presses Ctrl-C while the pipeline runs. Then:
20
+
21
+ 1. The signal aborts. Its reason is a `DOMException` with the name `AbortError` and the message `The process received SIGINT`.
22
+ 2. The pipeline stops at its next check of the signal, and `run()` returns.
23
+ 3. The `using` scopes end in reverse order: `warehouse` closes, then `shutdown`.
24
+ 4. The event loop has no more work. Node.js emits `'exit'`.
25
+ 5. The package removes each listener for SIGINT and sends SIGINT to its own process. The process dies by SIGINT.
26
+
27
+ SIGINT, SIGTERM and SIGHUP start a shutdown. SIGQUIT does not: Ctrl-\ keeps its default action, which ends the process and writes a core dump.
28
+
29
+ ## What the parent sees
30
+
31
+ | Cause of the shutdown | Exit status |
32
+ | ---------------------------------------------- | ---------------------------------------------------- |
33
+ | A termination signal | The process dies by that signal |
34
+ | A termination signal, and the process is PID 1 | Exit code 128 + the number of the signal (143) |
35
+ | A crash | Exit code 1, or the exit code the program set |
36
+ | No stop request | The exit code of the program, as without the package |
37
+
38
+ An exit code of 130 is not the same as a death by SIGINT. A Bash script stops its loop only when the child died by SIGINT. In a terminal, `node app.js && next` runs `next` after Ctrl-C when `app.js` exits with 0. When `app.js` dies by SIGINT, zsh stops the whole line. A parent that calls `waitpid()` sees the difference too: Node.js gives `signal: 'SIGINT'`, not `code: 130`.
39
+
40
+ ## A second stop request
41
+
42
+ The first stop request removes the termination signal listeners of the package. Thus a second termination signal gets the default action, and the process ends at once. Use this when the cleanup does not end. For example, a read from a pipe that no program writes waits in the thread pool of Node.js, and no signal can stop it. The second Ctrl-C ends the process.
43
+
44
+ The package has no timer. The supervisor owns the deadline of a shutdown:
45
+
46
+ | Supervisor | Deadline |
47
+ | ---------- | ---------------------------------------------------- |
48
+ | A terminal | The user presses Ctrl-C again |
49
+ | Docker | 10 s, then SIGKILL (`stop_grace_period` in Compose) |
50
+ | Kubernetes | 30 s, then SIGKILL (`terminationGracePeriodSeconds`) |
51
+ | systemd | 90 s, then SIGKILL (`TimeoutStopSec`) |
52
+ | Nx | 5 s, then SIGKILL (`NX_PROCESS_KILL_GRACE_PERIOD`) |
53
+
54
+ ## A crash
55
+
56
+ A crash is an exception that no code catches, or a rejection that no code handles. Without the package, Node.js writes the error and ends the process at once. With the package, a crash is a stop request:
57
+
58
+ 1. The package writes the error to standard error.
59
+ 2. The signal aborts. Its reason is the error of the crash.
60
+ 3. The work stops, and the cleanup runs, as for a termination signal.
61
+ 4. The process exits with code 1.
62
+
63
+ A second crash gets the default of Node.js: it writes the error and ends the process at once. A termination signal after the crash also ends the process at once.
64
+
65
+ The exit status always follows the cause. A crash during the cleanup of a SIGINT shutdown ends the process at once, and the process dies by SIGINT. For this case the package keeps its crash listeners after a termination signal: it writes the error, and then it sends SIGINT to its own process. The default of Node.js cannot do it, because Node.js emits `'exit'` before it writes the error of a crash.
66
+
67
+ ## Stop at the end of a scope
68
+
69
+ When the `using` scope of a `Shutdown` ends, the package removes its listeners and aborts the signal. Its reason is a `DOMException` with the name `AbortError` and the message `The shutdown scope ended`. This is not a stop request: the process does not die by a termination signal. After this, a termination signal gets the default action, and a crash gets the default of Node.js.
70
+
71
+ A stop request that came before the end of the scope stays. Then the end of the scope removes no listener, and the process still ends by its cause.
72
+
73
+ ## Run in a container
74
+
75
+ When the image starts the program with `CMD ["node", "main.js"]`, Node.js is PID 1. The kernel does not apply the default action of a signal to PID 1, so the process cannot die by the termination signal. Then the package sets the exit code to 128 + the number of the signal. Docker reports `Exited (143)` for SIGTERM.
76
+
77
+ Give the container an init process to make the process die by the signal:
78
+
79
+ ```yaml
80
+ services:
81
+ app:
82
+ image: app
83
+ init: true
84
+ stop_grace_period: 10s
85
+ ```
86
+
87
+ With `init: true`, tini is PID 1. The program dies by the signal, and tini gives that exit status to Docker.
88
+
89
+ ## Stop an HTTP server
90
+
91
+ The package does not stop a server. Node.js does most of it. An `http.Server` is `AsyncDisposable`, and `server.close()` stops new connections and closes the idle ones:
92
+
93
+ ```ts
94
+ import { aborted } from 'node:util';
95
+
96
+ import { Shutdown } from '@zukhruf/shutdown';
97
+
98
+ using shutdown = new Shutdown();
99
+ await using server = serve({ fetch: app.fetch, port });
100
+ await aborted(shutdown.signal, server);
101
+ setTimeout(() => server.closeAllConnections(), 1_000).unref();
102
+ ```
103
+
104
+ `util.aborted()` also settles when the signal aborted before the call. `events.once(signal, 'abort')` does not.
105
+
106
+ A probe on Node.js 26.10.0 compared this with `stoppable`, which `@godaddy/terminus` uses:
107
+
108
+ | Case | `stoppable` (grace 1000 ms) | `await using server` | With `closeAllConnections()` after 1 s |
109
+ | -------------------------------- | --------------------------- | -------------------- | -------------------------------------- |
110
+ | An idle keep-alive connection | 0 ms | 0 ms | 0 ms |
111
+ | A request that answers in 300 ms | 251 ms | 6254 ms | 1001 ms |
112
+ | A request that does not answer | 1001 ms | open after 3000 ms | 1001 ms |
113
+ | A new client after the stop | refused | refused | refused |
114
+
115
+ Node.js keeps a connection that becomes idle after the call to `close()` until `keepAliveTimeout` (5000 ms). It keeps a request that does not answer until `requestTimeout` (300 s). A server that must close faster needs a drainer that ends each connection after its last response, as `stoppable` does.
116
+
117
+ ## What the package does not do
118
+
119
+ - Stop an HTTP server, or make a health check answer 503 during a shutdown. Node.js and the HTTP framework do these. See [Stop an HTTP server](#stop-an-http-server).
120
+ - Run cleanup hooks. `using`, `await using` and `AsyncDisposableStack` run the cleanup, in reverse order.
121
+ - Stop the work for other causes. `AbortSignal.any([shutdown.signal, failed.signal])` gives a signal that also aborts when the program stops itself.
122
+ - Set a deadline. The supervisor sets it.
123
+ - Stop child processes. `@zukhruf/coprocess` stops them.
124
+ - A choice of termination signals. A program that must live on after its terminal closes runs under a supervisor or in tmux, not under `nohup`: a listener for SIGHUP replaces the ignore of `nohup`.
125
+ - Windows. Windows has no POSIX signals.
126
+
127
+ ## The same concepts in other systems
128
+
129
+ | Concept | Other systems |
130
+ | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
131
+ | Termination signals that cancel the work | `signal.NotifyContext` of [Go](https://pkg.go.dev/os/signal#NotifyContext); `CancellationToken` and `ctrl_c` of [tokio](https://tokio.rs/tokio/topics/shutdown); `ApplicationStopping` of the .NET Generic Host |
132
+ | Death by the signal after the cleanup | [Proper handling of SIGINT/SIGQUIT](https://www.cons.org/cracauer/sigint.html) (Cracauer); [Termination in Handler](https://sourceware.org/glibc/manual/latest/html_node/Termination-in-Handler.html) of the GNU C Library; `signal-exit`; `exitAsInterrupted()` of Nx |
133
+ | The default action for a second signal | `stop()` of Go's `NotifyContext`; the SIGINT watcher of Playwright |
134
+ | A crash that starts a graceful shutdown | `close-with-grace`, which the `eject` server templates of fastify-cli use |
135
+ | An init process in a container | `docker run --init` and tini |
136
+
137
+ ## API
138
+
139
+ ```ts
140
+ export class Shutdown implements Disposable {
141
+ /** Listens for SIGINT, SIGTERM, SIGHUP, uncaught exceptions and unhandled rejections. */
142
+ constructor();
143
+
144
+ /** Aborts at the first stop request. Its reason is the cause. */
145
+ readonly signal: AbortSignal;
146
+
147
+ /** Removes the listeners and aborts the signal. A stop request that came before stays. */
148
+ [Symbol.dispose](): void;
149
+ }
150
+ ```
151
+
152
+ | Call or event | What the package does |
153
+ | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
154
+ | `new Shutdown()` | `process.on()` for SIGINT, SIGTERM, SIGHUP, `'uncaughtException'`, `'unhandledRejection'` and `'exit'` |
155
+ | The first termination signal | `process.off()` for each termination signal listener of the package, then `AbortController.abort()` with the `AbortError` |
156
+ | The first crash | `console.error()` of the error, `process.off()` for each termination signal and crash listener of the package, then `abort()` with the error |
157
+ | A crash after a termination signal | `console.error()` of the error, then `process.exit()`. The `'exit'` listener then ends the process by the signal |
158
+ | `'exit'` after a termination signal | `process.removeAllListeners()` for that termination signal, then `process.kill(process.pid, signal)`. When the process still runs: `process.exitCode = 128 + n` (`util.convertProcessSignalToExitCode()`) |
159
+ | `'exit'` after a crash | `process.exitCode \|\|= 1`: exit code 1, unless the program set a failure code |
160
+ | `[Symbol.dispose]()` | With no stop request: `process.off()` for each listener of the package, `'exit'` too, then `abort()`. After a stop request: nothing |
161
+
162
+ ## Who uses each part
163
+
164
+ The consumers below come from the search of 2026-11-02. None of them dies by the termination signal today. The package itself is backlog mutex #3579.
165
+
166
+ | Consumer | Uses | Backlog |
167
+ | ------------------------------------------------------------------------ | ----------------------------- | ---------------------- |
168
+ | context-compiler: logful, startup-credits and its eval, what-is-going-on | `signal`, the exit status | context-compiler #3580 |
169
+ | context-compiler: the MCP server of the Codex plugin | `signal`, to close the server | context-compiler #3580 |
170
+ | elt: the proactive app | `signal`, the exit status | elt #3581 |
@@ -0,0 +1,2 @@
1
+ export { Shutdown } from './shutdown.ts';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { Shutdown } from "./shutdown.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare class Shutdown implements Disposable {
2
+ #private;
3
+ constructor();
4
+ get signal(): AbortSignal;
5
+ [Symbol.dispose](): void;
6
+ }
7
+ //# sourceMappingURL=shutdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../src/shutdown.ts"],"names":[],"mappings":"AAgBA,qBAAa,QAAS,YAAW,UAAU;;;IAoDzC,IAAI,MAAM,IAAI,WAAW,CAExB;IAgBD,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI;CAWzB"}
@@ -0,0 +1,82 @@
1
+ import { convertProcessSignalToExitCode } from 'node:util';
2
+ const terminationSignals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
3
+ /** The reason of the signal when a termination signal is the cause. */
4
+ class TerminationSignalReceived extends DOMException {
5
+ terminationSignal;
6
+ constructor(terminationSignal) {
7
+ super(`The process received ${terminationSignal}`, 'AbortError');
8
+ this.terminationSignal = terminationSignal;
9
+ }
10
+ }
11
+ export class Shutdown {
12
+ #controller = new AbortController();
13
+ // A second termination signal gets the default action (ADR 0002). The
14
+ // crash listeners stay: see #onCrash.
15
+ #onTerminationSignal = (signal) => {
16
+ this.#stopListeningForSignals();
17
+ this.#controller.abort(new TerminationSignalReceived(signal));
18
+ };
19
+ // With a listener, Node.js does not write the error, so the package does
20
+ // (ADR 0003). A crash after a termination signal ends the process at once:
21
+ // process.exit() emits 'exit', and there the process dies by the signal.
22
+ // The default of Node.js would lose the error: with no listener, it emits
23
+ // 'exit' before it writes the error (lib/internal/process/execution.js).
24
+ #onCrash = (error) => {
25
+ console.error(error);
26
+ if (this.#controller.signal.reason instanceof TerminationSignalReceived) {
27
+ process.exit();
28
+ }
29
+ this.#stopListeningForSignals();
30
+ this.#stopListeningForCrashes();
31
+ this.#controller.abort(error);
32
+ };
33
+ // After the cleanup, the process dies by the termination signal that caused
34
+ // the shutdown (ADR 0001). The other listeners for that signal go first, or
35
+ // one of them would take it. The kernel does not apply the default action
36
+ // to PID 1, so there the process lives on, and it exits with the code that a
37
+ // shell shows for the signal. After a crash, the exit code is 1 (ADR 0003).
38
+ #onExit = () => {
39
+ const cause = this.#controller.signal.reason;
40
+ if (cause instanceof TerminationSignalReceived) {
41
+ process.removeAllListeners(cause.terminationSignal);
42
+ process.kill(process.pid, cause.terminationSignal);
43
+ process.exitCode = convertProcessSignalToExitCode(cause.terminationSignal);
44
+ }
45
+ else if (this.#controller.signal.aborted) {
46
+ process.exitCode ||= 1;
47
+ }
48
+ };
49
+ constructor() {
50
+ for (const signal of terminationSignals) {
51
+ process.on(signal, this.#onTerminationSignal);
52
+ }
53
+ process.on('uncaughtException', this.#onCrash);
54
+ process.on('unhandledRejection', this.#onCrash);
55
+ process.on('exit', this.#onExit);
56
+ }
57
+ get signal() {
58
+ return this.#controller.signal;
59
+ }
60
+ #stopListeningForSignals() {
61
+ for (const signal of terminationSignals) {
62
+ process.off(signal, this.#onTerminationSignal);
63
+ }
64
+ }
65
+ #stopListeningForCrashes() {
66
+ process.off('uncaughtException', this.#onCrash);
67
+ process.off('unhandledRejection', this.#onCrash);
68
+ }
69
+ // A stop request that came before the end of the scope stays. Each listener
70
+ // left after it ends the process by its cause, so the end of the scope
71
+ // removes none of them.
72
+ [Symbol.dispose]() {
73
+ if (this.#controller.signal.aborted) {
74
+ return;
75
+ }
76
+ this.#stopListeningForSignals();
77
+ this.#stopListeningForCrashes();
78
+ process.off('exit', this.#onExit);
79
+ this.#controller.abort(new DOMException('The shutdown scope ended', 'AbortError'));
80
+ }
81
+ }
82
+ //# sourceMappingURL=shutdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../src/shutdown.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,47 @@
1
1
  {
2
2
  "name": "@zukhruf/shutdown",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.6.13",
4
+ "description": "A graceful shutdown for a Node.js program: SIGINT, SIGTERM, SIGHUP and crashes abort one AbortSignal, the program runs its cleanup, and then the process dies by the termination signal, so a shell, Docker or Kubernetes sees an interrupted process.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/JanuaryLabs/zukhruf",
9
+ "directory": "packages/shutdown"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/JanuaryLabs/zukhruf/issues"
13
+ },
14
+ "homepage": "https://github.com/JanuaryLabs/zukhruf/tree/main/packages/shutdown#readme",
15
+ "keywords": [
16
+ "shutdown",
17
+ "graceful-shutdown",
18
+ "signal",
19
+ "sigint",
20
+ "sigterm",
21
+ "sighup",
22
+ "abortsignal",
23
+ "exit"
24
+ ],
25
+ "type": "module",
26
+ "exports": {
27
+ "./package.json": "./package.json",
28
+ ".": {
29
+ "@zukhruf/source": "./src/index.ts",
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js",
32
+ "default": "./dist/index.js"
33
+ }
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "!dist/spec/**",
38
+ "!**/*.tsbuildinfo",
39
+ "!**/*.test.*"
40
+ ],
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "devDependencies": {
45
+ "@zukhruf/docker": "^0.6.13"
46
+ }
47
+ }