bare-stow 0.1.8 → 0.1.9

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/README.md CHANGED
@@ -91,7 +91,7 @@ The `ipc` handle exposes the lifecycle as events and methods on the same duplex:
91
91
 
92
92
  - `ipc.ready`: A promise that resolves once the worker has signaled ready. Rejects if the worker errors before ready.
93
93
  - `ipc.on('exit', code)`: Emitted when the worker signals exit. `code` carries the exit code.
94
- - `ipc.on('error', err)`: Emitted when the worker reports a fault, or when the underlying transport errors. Either way the `ipc` is destroyed.
94
+ - `ipc.on('error', err)`: Emitted when the worker reports a fault, when it exits without saying why, such as through `Bare.exit()`, a signal, or a crash, or when the underlying transport errors. Either way the `ipc` is destroyed. For a worker that exited without saying why, `err.exitCode` and `err.signalCode` carry the reason.
95
95
  - `ipc.on('close')`: Emitted when the underlying transport closes.
96
96
  - `ipc.destroy()`: Standard stream destroy. Sends a `terminate` control frame to the worker and waits for the underlying transport to close.
97
97
  - `ipc.terminate()`: Like `destroy()` but resolves with the worker's exit code.
package/lib/host.d.ts CHANGED
@@ -32,6 +32,14 @@ interface IPC extends Protocol {
32
32
  * @returns The worker's exit `code`, or `undefined` if it closed without signaling one.
33
33
  */
34
34
  terminate(): Promise<number | undefined>
35
+ /**
36
+ * Report that the worker has exited, as observed by the transport. If the worker exited without
37
+ * saying why and was not asked to, the handle is destroyed with an error carrying the reason as
38
+ * `exitCode` and `signalCode`.
39
+ * @param code - The exit code of the worker, or `null` if it was killed by a signal.
40
+ * @param signal - The signal that killed the worker, or `null` (default `null`).
41
+ */
42
+ exited(code: number | null, signal?: string | null): void
35
43
  }
36
44
 
37
45
  declare class IPC {
package/lib/host.js CHANGED
@@ -9,6 +9,11 @@ class IPC extends Protocol {
9
9
  this._kill = kill
10
10
  this._grace = grace
11
11
  this._terminating = null
12
+ this._exitReported = false
13
+
14
+ this.once('exit', () => {
15
+ this._exitReported = true
16
+ })
12
17
 
13
18
  this.send('configure', { grace })
14
19
 
@@ -64,6 +69,20 @@ class IPC extends Protocol {
64
69
  })
65
70
  }
66
71
 
72
+ exited(code, signal = null) {
73
+ // The worker either said why it exited or was asked to.
74
+ if (this._exitReported || this._terminating !== null || this.destroying) return
75
+
76
+ const err = new Error(
77
+ signal === null ? `Worker exited with code ${code}` : `Worker was killed by ${signal}`
78
+ )
79
+
80
+ err.exitCode = code
81
+ err.signalCode = signal
82
+
83
+ this.destroy(err)
84
+ }
85
+
67
86
  _destroy(err, cb) {
68
87
  if (this._stream.destroyed) return cb(null)
69
88
 
@@ -34,7 +34,9 @@ const bundle = new URL(import.meta.resolve(${JSON.stringify(bundleSpecifier)}))
34
34
  export async function start({ timeout, grace, ...opts } = {}) {
35
35
  const sidecar = new Sidecar(bundle, { stdio: 'inherit', ...opts })
36
36
 
37
- const ${ipc} = stow.wrap(sidecar, { timeout, grace })
37
+ const ${ipc} = stow.wrap(sidecar, { kill: () => sidecar.kill('SIGKILL'), timeout, grace })
38
+
39
+ sidecar.on('exit', (code, signal) => ${ipc}.exited(code, signal))
38
40
  ${client ? '\n' + indent(client.source, 2) : ''}
39
41
  await ${ipc}.ready
40
42
 
@@ -51,7 +53,9 @@ module.exports = {
51
53
  async start({ timeout, grace, ...opts } = {}) {
52
54
  const sidecar = new Sidecar(bundle, { stdio: 'inherit', ...opts })
53
55
 
54
- const ${ipc} = stow.wrap(sidecar, { timeout, grace })
56
+ const ${ipc} = stow.wrap(sidecar, { kill: () => sidecar.kill('SIGKILL'), timeout, grace })
57
+
58
+ sidecar.on('exit', (code, signal) => ${ipc}.exited(code, signal))
55
59
  ${client ? '\n' + indent(client.source, 4) : ''}
56
60
  await ${ipc}.ready
57
61
 
@@ -38,6 +38,8 @@ export async function start({ timeout, grace, ...opts } = {}) {
38
38
 
39
39
  // The IPC stream of a worker ends, but never closes, when its thread exits.
40
40
  worker.IPC.on('end', () => worker.IPC.destroy())
41
+
42
+ worker.on('exit', (code) => ${ipc}.exited(code))
41
43
  ${client ? '\n' + indent(client.source, 2) : ''}
42
44
  await ${ipc}.ready
43
45
 
@@ -58,6 +60,8 @@ module.exports = {
58
60
 
59
61
  // The IPC stream of a worker ends, but never closes, when its thread exits.
60
62
  worker.IPC.on('end', () => worker.IPC.destroy())
63
+
64
+ worker.on('exit', (code) => ${ipc}.exited(code))
61
65
  ${client ? '\n' + indent(client.source, 4) : ''}
62
66
  await ${ipc}.ready
63
67
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bare-stow",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Module bundling and harness generation for Bare",
5
5
  "exports": {
6
6
  "./package": "./package.json",
@@ -80,8 +80,9 @@
80
80
  "paparam": "^1.5.0"
81
81
  },
82
82
  "devDependencies": {
83
+ "bare-os": "^3.0.0",
83
84
  "bare-rpc": "^1.3.2",
84
- "bare-sidecar": "^0.5.9",
85
+ "bare-sidecar": "^0.5.11",
85
86
  "bare-worker": "^4.3.0",
86
87
  "brittle": "^4.0.2",
87
88
  "lunte": "^1.7.0",