@travetto/runtime 7.1.2 → 7.1.3
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 +1 -3
- package/package.json +3 -3
- package/src/context.ts +0 -5
- package/src/exec.ts +7 -19
- package/src/shutdown.ts +14 -19
package/README.md
CHANGED
|
@@ -51,8 +51,6 @@ class $Runtime {
|
|
|
51
51
|
get monoRoot(): boolean;
|
|
52
52
|
/** Main source path */
|
|
53
53
|
get mainSourcePath(): string;
|
|
54
|
-
/** Get trv entrypoint */
|
|
55
|
-
get trvEntryPoint(): string;
|
|
56
54
|
/** Produce a workspace relative path */
|
|
57
55
|
workspaceRelative(...parts: string[]): string;
|
|
58
56
|
/** Strip off the workspace path from a file */
|
|
@@ -323,7 +321,7 @@ export class TimeUtil {
|
|
|
323
321
|
```
|
|
324
322
|
|
|
325
323
|
## Process Execution
|
|
326
|
-
[ExecUtil](https://github.com/travetto/travetto/tree/main/module/runtime/src/exec.ts#
|
|
324
|
+
[ExecUtil](https://github.com/travetto/travetto/tree/main/module/runtime/src/exec.ts#L42) exposes `getResult` as a means to wrap [child_process](https://nodejs.org/api/child_process.html)'s process object. This wrapper allows for a promise-based resolution of the subprocess with the ability to capture the stderr/stdout.
|
|
327
325
|
|
|
328
326
|
A simple example would be:
|
|
329
327
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/runtime",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Runtime for travetto applications.",
|
|
6
6
|
"keywords": [
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"directory": "module/runtime"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@travetto/manifest": "^7.1.
|
|
29
|
+
"@travetto/manifest": "^7.1.2",
|
|
30
30
|
"@types/debug": "^4.1.12",
|
|
31
31
|
"debug": "^4.4.3"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@travetto/transformer": "^7.1.
|
|
34
|
+
"@travetto/transformer": "^7.1.2"
|
|
35
35
|
},
|
|
36
36
|
"peerDependenciesMeta": {
|
|
37
37
|
"@travetto/transformer": {
|
package/src/context.ts
CHANGED
|
@@ -68,11 +68,6 @@ class $Runtime {
|
|
|
68
68
|
return this.#idx.mainModule.sourcePath;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
/** Get trv entrypoint */
|
|
72
|
-
get trvEntryPoint(): string {
|
|
73
|
-
return this.workspaceRelative('node_modules', '.bin', 'trv');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
71
|
/** Produce a workspace relative path */
|
|
77
72
|
workspaceRelative(...parts: string[]): string {
|
|
78
73
|
return path.resolve(this.workspace.path, ...parts);
|
package/src/exec.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { type ChildProcess } from 'node:child_process';
|
|
1
|
+
import { type ChildProcess, spawn, type SpawnOptions } from 'node:child_process';
|
|
2
2
|
import type { Readable } from 'node:stream';
|
|
3
3
|
import { createInterface } from 'node:readline/promises';
|
|
4
4
|
|
|
5
5
|
import { castTo } from './types.ts';
|
|
6
|
+
import { RuntimeIndex } from './manifest-index.ts';
|
|
6
7
|
|
|
7
8
|
const ResultSymbol = Symbol();
|
|
8
9
|
|
|
@@ -39,24 +40,6 @@ type ExecutionBaseResult = Omit<ExecutionResult, 'stdout' | 'stderr'>;
|
|
|
39
40
|
*/
|
|
40
41
|
export class ExecUtil {
|
|
41
42
|
|
|
42
|
-
/**
|
|
43
|
-
* Defer control to subprocess execution, mainly used for nested execution
|
|
44
|
-
*/
|
|
45
|
-
static async deferToSubprocess(child: ChildProcess): Promise<ExecutionResult> {
|
|
46
|
-
const messageToChild = (value: unknown): void => { child.send(value!); };
|
|
47
|
-
const messageToParent = (value: unknown): void => { process.send?.(value); };
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
process.on('message', messageToChild);
|
|
51
|
-
child.on('message', messageToParent);
|
|
52
|
-
const result = await this.getResult(child, { catch: true });
|
|
53
|
-
process.exitCode = child.exitCode;
|
|
54
|
-
return result;
|
|
55
|
-
} finally {
|
|
56
|
-
process.off('message', messageToChild);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
43
|
/**
|
|
61
44
|
* Take a child process, and some additional options, and produce a promise that
|
|
62
45
|
* represents the entire execution. On successful completion the promise will resolve, and
|
|
@@ -128,4 +111,9 @@ export class ExecUtil {
|
|
|
128
111
|
await handler(item);
|
|
129
112
|
}
|
|
130
113
|
}
|
|
114
|
+
|
|
115
|
+
/** Spawn a package command */
|
|
116
|
+
static spawnPackageCommand(cmd: string, args: string[], config: SpawnOptions = {}): ChildProcess {
|
|
117
|
+
return spawn(process.argv0, [RuntimeIndex.resolvePackageCommand(cmd), ...args], config);
|
|
118
|
+
}
|
|
131
119
|
}
|
package/src/shutdown.ts
CHANGED
|
@@ -11,8 +11,7 @@ const REASON_TO_CODE = new Map<ShutdownReason, number>(MAPPING);
|
|
|
11
11
|
const CODE_TO_REASON = new Map<number, ShutdownReason>(MAPPING.map(([k, v]) => [v, k]));
|
|
12
12
|
|
|
13
13
|
type Handler = (event: Event) => unknown;
|
|
14
|
-
type
|
|
15
|
-
type ShutdownEvent = { signal?: ShutdownSignal, reason?: ShutdownReason | number, exit?: boolean };
|
|
14
|
+
type ShutdownEvent = { reason?: ShutdownReason, mode?: 'exit' | 'interrupt' };
|
|
16
15
|
|
|
17
16
|
const isShutdownEvent = (event: unknown): event is ShutdownEvent =>
|
|
18
17
|
typeof event === 'object' && event !== null && 'type' in event && event.type === 'shutdown';
|
|
@@ -36,11 +35,12 @@ export class ShutdownManager {
|
|
|
36
35
|
static {
|
|
37
36
|
this.#controller.signal.addEventListener = (_: 'abort', listener: Handler): void => { this.#registered.add(listener); };
|
|
38
37
|
this.#controller.signal.removeEventListener = (_: 'abort', listener: Handler): void => { this.#registered.delete(listener); };
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
try {
|
|
39
|
+
process
|
|
40
|
+
.on('message', event => { isShutdownEvent(event) && this.shutdown(event); })
|
|
41
|
+
.on('SIGINT', () => this.shutdown({ mode: 'interrupt' }))
|
|
42
|
+
.on('SIGTERM', () => this.shutdown());
|
|
43
|
+
} catch { }
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
static get signal(): AbortSignal {
|
|
@@ -66,29 +66,24 @@ export class ShutdownManager {
|
|
|
66
66
|
/**
|
|
67
67
|
* Shutdown the application gracefully
|
|
68
68
|
*/
|
|
69
|
-
static async shutdown(
|
|
70
|
-
if ((
|
|
69
|
+
static async shutdown({ reason = 'quit', mode = undefined }: ShutdownEvent = {}): Promise<void> {
|
|
70
|
+
if ((mode === 'interrupt' && this.#shouldIgnoreInterrupt) || this.#controller.signal.aborted) {
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
process // Allow shutdown if anything is still listening
|
|
75
75
|
.removeAllListeners('message')
|
|
76
76
|
.removeAllListeners('SIGINT')
|
|
77
|
-
.removeAllListeners('SIGTERM')
|
|
78
|
-
.removeAllListeners('SIGUSR2');
|
|
77
|
+
.removeAllListeners('SIGTERM');
|
|
79
78
|
|
|
80
|
-
if (
|
|
79
|
+
if (mode === 'interrupt' && process.stdout.isTTY) {
|
|
81
80
|
process.stdout.write('\n');
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
|
|
85
|
-
const { reason } = event;
|
|
86
|
-
process.exitCode = (typeof reason === 'string' ? REASON_TO_CODE.get(reason) : reason);
|
|
87
|
-
}
|
|
83
|
+
process.exitCode ??= REASON_TO_CODE.get(reason);
|
|
88
84
|
|
|
89
85
|
const timeout = TimeUtil.fromValue(Env.TRV_SHUTDOWN_WAIT.value) ?? 2000;
|
|
90
|
-
const context = {
|
|
91
|
-
|
|
86
|
+
const context = { reason, mode, pid: process.pid, timeout, pending: this.#registered.size };
|
|
92
87
|
this.#controller.abort('Shutdown started');
|
|
93
88
|
console.debug('Shutdown started', context);
|
|
94
89
|
|
|
@@ -103,7 +98,7 @@ export class ShutdownManager {
|
|
|
103
98
|
console.warn('Shutdown timed out', context);
|
|
104
99
|
}
|
|
105
100
|
|
|
106
|
-
if (
|
|
101
|
+
if (mode === 'exit') {
|
|
107
102
|
process.exit();
|
|
108
103
|
}
|
|
109
104
|
}
|