nx 20.5.0-canary.20250204-bc4ded0 → 21.0.0-beta.0
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/package.json +12 -11
- package/src/command-line/graph/graph.js +2 -0
- package/src/commands-runner/get-command-projects.js +17 -2
- package/src/config/task-graph.d.ts +5 -0
- package/src/config/workspace-json-project-json.d.ts +4 -0
- package/src/executors/run-commands/run-commands.impl.d.ts +16 -13
- package/src/executors/run-commands/run-commands.impl.js +24 -263
- package/src/executors/run-commands/running-tasks.d.ts +38 -0
- package/src/executors/run-commands/running-tasks.js +349 -0
- package/src/native/index.d.ts +1 -0
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/tasks-runner/create-task-graph.d.ts +3 -0
- package/src/tasks-runner/create-task-graph.js +36 -5
- package/src/tasks-runner/forked-process-task-runner.d.ts +6 -12
- package/src/tasks-runner/forked-process-task-runner.js +110 -263
- package/src/tasks-runner/init-tasks-runner.js +4 -0
- package/src/tasks-runner/pseudo-terminal.d.ts +7 -1
- package/src/tasks-runner/pseudo-terminal.js +26 -12
- package/src/tasks-runner/running-tasks/batch-process.d.ts +14 -0
- package/src/tasks-runner/running-tasks/batch-process.js +70 -0
- package/src/tasks-runner/running-tasks/node-child-process.d.ts +36 -0
- package/src/tasks-runner/running-tasks/node-child-process.js +184 -0
- package/src/tasks-runner/running-tasks/noop-child-process.d.ts +15 -0
- package/src/tasks-runner/running-tasks/noop-child-process.js +19 -0
- package/src/tasks-runner/running-tasks/running-task.d.ts +8 -0
- package/src/tasks-runner/running-tasks/running-task.js +6 -0
- package/src/tasks-runner/task-orchestrator.d.ts +7 -1
- package/src/tasks-runner/task-orchestrator.js +137 -82
- package/src/tasks-runner/tasks-schedule.js +5 -1
- package/src/tasks-runner/utils.d.ts +0 -8
- package/src/tasks-runner/utils.js +12 -4
@@ -3,15 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ForkedProcessTaskRunner = void 0;
|
4
4
|
const fs_1 = require("fs");
|
5
5
|
const child_process_1 = require("child_process");
|
6
|
-
const chalk = require("chalk");
|
7
6
|
const output_1 = require("../utils/output");
|
8
7
|
const utils_1 = require("./utils");
|
9
8
|
const path_1 = require("path");
|
10
9
|
const batch_messages_1 = require("./batch/batch-messages");
|
11
10
|
const strip_indents_1 = require("../utils/strip-indents");
|
12
|
-
const stream_1 = require("stream");
|
13
11
|
const pseudo_terminal_1 = require("./pseudo-terminal");
|
14
12
|
const exit_codes_1 = require("../utils/exit-codes");
|
13
|
+
const node_child_process_1 = require("./running-tasks/node-child-process");
|
14
|
+
const batch_process_1 = require("./running-tasks/batch-process");
|
15
15
|
const forkScript = (0, path_1.join)(__dirname, './fork.js');
|
16
16
|
const workerPath = (0, path_1.join)(__dirname, './batch/run-batch.js');
|
17
17
|
class ForkedProcessTaskRunner {
|
@@ -31,76 +31,42 @@ class ForkedProcessTaskRunner {
|
|
31
31
|
this.setupProcessEventListeners();
|
32
32
|
}
|
33
33
|
// TODO: vsavkin delegate terminal output printing
|
34
|
-
forkProcessForBatch({ executorName, taskGraph: batchTaskGraph }, fullTaskGraph, env) {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
success: false,
|
59
|
-
terminalOutput: '',
|
60
|
-
};
|
61
|
-
}
|
62
|
-
rej(new Error(`"${executorName}" exited unexpectedly with code: ${code}`));
|
63
|
-
}
|
64
|
-
});
|
65
|
-
p.on('message', (message) => {
|
66
|
-
switch (message.type) {
|
67
|
-
case batch_messages_1.BatchMessageType.CompleteBatchExecution: {
|
68
|
-
res(message.results);
|
69
|
-
break;
|
70
|
-
}
|
71
|
-
case batch_messages_1.BatchMessageType.RunTasks: {
|
72
|
-
break;
|
73
|
-
}
|
74
|
-
default: {
|
75
|
-
// Re-emit any non-batch messages from the task process
|
76
|
-
if (process.send) {
|
77
|
-
process.send(message);
|
78
|
-
}
|
79
|
-
}
|
80
|
-
}
|
81
|
-
});
|
82
|
-
// Start the tasks
|
83
|
-
p.send({
|
84
|
-
type: batch_messages_1.BatchMessageType.RunTasks,
|
85
|
-
executorName,
|
86
|
-
batchTaskGraph,
|
87
|
-
fullTaskGraph,
|
88
|
-
});
|
89
|
-
}
|
90
|
-
catch (e) {
|
91
|
-
rej(e);
|
92
|
-
}
|
34
|
+
async forkProcessForBatch({ executorName, taskGraph: batchTaskGraph }, fullTaskGraph, env) {
|
35
|
+
const count = Object.keys(batchTaskGraph.tasks).length;
|
36
|
+
if (count > 1) {
|
37
|
+
output_1.output.logSingleLine(`Running ${output_1.output.bold(count)} ${output_1.output.bold('tasks')} with ${output_1.output.bold(executorName)}`);
|
38
|
+
}
|
39
|
+
else {
|
40
|
+
const args = (0, utils_1.getPrintableCommandArgsForTask)(Object.values(batchTaskGraph.tasks)[0]);
|
41
|
+
output_1.output.logCommand(args.join(' '));
|
42
|
+
}
|
43
|
+
const p = (0, child_process_1.fork)(workerPath, {
|
44
|
+
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
45
|
+
env,
|
46
|
+
});
|
47
|
+
const cp = new batch_process_1.BatchProcess(p, executorName);
|
48
|
+
this.processes.add(cp);
|
49
|
+
cp.onExit(() => {
|
50
|
+
this.processes.delete(cp);
|
51
|
+
});
|
52
|
+
// Start the tasks
|
53
|
+
cp.send({
|
54
|
+
type: batch_messages_1.BatchMessageType.RunTasks,
|
55
|
+
executorName,
|
56
|
+
batchTaskGraph,
|
57
|
+
fullTaskGraph,
|
93
58
|
});
|
59
|
+
return cp;
|
94
60
|
}
|
95
61
|
async forkProcessLegacy(task, { temporaryOutputPath, streamOutput, pipeOutput, taskGraph, env, }) {
|
96
62
|
return pipeOutput
|
97
|
-
?
|
63
|
+
? this.forkProcessWithPrefixAndNotTTY(task, {
|
98
64
|
temporaryOutputPath,
|
99
65
|
streamOutput,
|
100
66
|
taskGraph,
|
101
67
|
env,
|
102
68
|
})
|
103
|
-
:
|
69
|
+
: this.forkProcessDirectOutputCapture(task, {
|
104
70
|
temporaryOutputPath,
|
105
71
|
streamOutput,
|
106
72
|
taskGraph,
|
@@ -154,158 +120,96 @@ class ForkedProcessTaskRunner {
|
|
154
120
|
p.onOutput((msg) => {
|
155
121
|
terminalOutput += msg;
|
156
122
|
});
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
this.writeTerminalOutput(temporaryOutputPath, terminalOutput);
|
164
|
-
res({
|
165
|
-
code,
|
166
|
-
terminalOutput,
|
167
|
-
});
|
168
|
-
});
|
169
|
-
});
|
170
|
-
}
|
171
|
-
forkProcessPipeOutputCapture(task, { streamOutput, temporaryOutputPath, taskGraph, env, }) {
|
172
|
-
return this.forkProcessWithPrefixAndNotTTY(task, {
|
173
|
-
streamOutput,
|
174
|
-
temporaryOutputPath,
|
175
|
-
taskGraph,
|
176
|
-
env,
|
123
|
+
p.onExit((code) => {
|
124
|
+
if (code > 128) {
|
125
|
+
process.exit(code);
|
126
|
+
}
|
127
|
+
this.processes.delete(p);
|
128
|
+
this.writeTerminalOutput(temporaryOutputPath, terminalOutput);
|
177
129
|
});
|
130
|
+
return p;
|
178
131
|
}
|
179
132
|
forkProcessWithPrefixAndNotTTY(task, { streamOutput, temporaryOutputPath, taskGraph, env, }) {
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
if (process.env.NX_PREFIX_OUTPUT === 'true') {
|
206
|
-
const color = getColor(task.target.project);
|
207
|
-
const prefixText = `${task.target.project}:`;
|
208
|
-
p.stdout
|
209
|
-
.pipe(logClearLineToPrefixTransformer(color.bold(prefixText) + ' '))
|
210
|
-
.pipe(addPrefixTransformer(color.bold(prefixText)))
|
211
|
-
.pipe(process.stdout);
|
212
|
-
p.stderr
|
213
|
-
.pipe(logClearLineToPrefixTransformer(color(prefixText) + ' '))
|
214
|
-
.pipe(addPrefixTransformer(color(prefixText)))
|
215
|
-
.pipe(process.stderr);
|
216
|
-
}
|
217
|
-
else {
|
218
|
-
p.stdout.pipe(addPrefixTransformer()).pipe(process.stdout);
|
219
|
-
p.stderr.pipe(addPrefixTransformer()).pipe(process.stderr);
|
220
|
-
}
|
133
|
+
try {
|
134
|
+
const args = (0, utils_1.getPrintableCommandArgsForTask)(task);
|
135
|
+
if (streamOutput) {
|
136
|
+
output_1.output.logCommand(args.join(' '));
|
137
|
+
}
|
138
|
+
const p = (0, child_process_1.fork)(this.cliPath, {
|
139
|
+
stdio: ['inherit', 'pipe', 'pipe', 'ipc'],
|
140
|
+
env,
|
141
|
+
});
|
142
|
+
// Send message to run the executor
|
143
|
+
p.send({
|
144
|
+
targetDescription: task.target,
|
145
|
+
overrides: task.overrides,
|
146
|
+
taskGraph,
|
147
|
+
isVerbose: this.verbose,
|
148
|
+
});
|
149
|
+
const cp = new node_child_process_1.NodeChildProcessWithNonDirectOutput(p, {
|
150
|
+
streamOutput,
|
151
|
+
prefix: task.target.project,
|
152
|
+
});
|
153
|
+
this.processes.add(cp);
|
154
|
+
cp.onExit((code, terminalOutput) => {
|
155
|
+
this.processes.delete(cp);
|
156
|
+
if (!streamOutput) {
|
157
|
+
this.options.lifeCycle.printTaskTerminalOutput(task, code === 0 ? 'success' : 'failure', terminalOutput);
|
221
158
|
}
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
159
|
+
this.writeTerminalOutput(temporaryOutputPath, terminalOutput);
|
160
|
+
});
|
161
|
+
return cp;
|
162
|
+
}
|
163
|
+
catch (e) {
|
164
|
+
console.error(e);
|
165
|
+
throw e;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
forkProcessDirectOutputCapture(task, { streamOutput, temporaryOutputPath, taskGraph, env, }) {
|
169
|
+
try {
|
170
|
+
const args = (0, utils_1.getPrintableCommandArgsForTask)(task);
|
171
|
+
if (streamOutput) {
|
172
|
+
output_1.output.logCommand(args.join(' '));
|
173
|
+
}
|
174
|
+
const p = (0, child_process_1.fork)(this.cliPath, {
|
175
|
+
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
176
|
+
env,
|
177
|
+
});
|
178
|
+
const cp = new node_child_process_1.NodeChildProcessWithDirectOutput(p, temporaryOutputPath);
|
179
|
+
this.processes.add(cp);
|
180
|
+
// Send message to run the executor
|
181
|
+
p.send({
|
182
|
+
targetDescription: task.target,
|
183
|
+
overrides: task.overrides,
|
184
|
+
taskGraph,
|
185
|
+
isVerbose: this.verbose,
|
186
|
+
});
|
187
|
+
cp.onExit((code, signal) => {
|
188
|
+
this.processes.delete(cp);
|
189
|
+
// we didn't print any output as we were running the command
|
190
|
+
// print all the collected output
|
191
|
+
try {
|
192
|
+
const terminalOutput = cp.getTerminalOutput();
|
236
193
|
if (!streamOutput) {
|
237
194
|
this.options.lifeCycle.printTaskTerminalOutput(task, code === 0 ? 'success' : 'failure', terminalOutput);
|
238
195
|
}
|
239
|
-
this.writeTerminalOutput(temporaryOutputPath, terminalOutput);
|
240
|
-
res({ code, terminalOutput });
|
241
|
-
});
|
242
|
-
}
|
243
|
-
catch (e) {
|
244
|
-
console.error(e);
|
245
|
-
rej(e);
|
246
|
-
}
|
247
|
-
});
|
248
|
-
}
|
249
|
-
forkProcessDirectOutputCapture(task, { streamOutput, temporaryOutputPath, taskGraph, env, }) {
|
250
|
-
return new Promise((res, rej) => {
|
251
|
-
try {
|
252
|
-
const args = (0, utils_1.getPrintableCommandArgsForTask)(task);
|
253
|
-
if (streamOutput) {
|
254
|
-
output_1.output.logCommand(args.join(' '));
|
255
196
|
}
|
256
|
-
|
257
|
-
|
258
|
-
env,
|
259
|
-
});
|
260
|
-
this.processes.add(p);
|
261
|
-
// Re-emit any messages from the task process
|
262
|
-
p.on('message', (message) => {
|
263
|
-
if (process.send) {
|
264
|
-
process.send(message);
|
265
|
-
}
|
266
|
-
});
|
267
|
-
// Send message to run the executor
|
268
|
-
p.send({
|
269
|
-
targetDescription: task.target,
|
270
|
-
overrides: task.overrides,
|
271
|
-
taskGraph,
|
272
|
-
isVerbose: this.verbose,
|
273
|
-
});
|
274
|
-
p.on('exit', (code, signal) => {
|
275
|
-
if (code === null)
|
276
|
-
code = (0, exit_codes_1.signalToCode)(signal);
|
277
|
-
// we didn't print any output as we were running the command
|
278
|
-
// print all the collected output
|
279
|
-
let terminalOutput = '';
|
280
|
-
try {
|
281
|
-
terminalOutput = this.readTerminalOutput(temporaryOutputPath);
|
282
|
-
if (!streamOutput) {
|
283
|
-
this.options.lifeCycle.printTaskTerminalOutput(task, code === 0 ? 'success' : 'failure', terminalOutput);
|
284
|
-
}
|
285
|
-
}
|
286
|
-
catch (e) {
|
287
|
-
console.log((0, strip_indents_1.stripIndents) `
|
197
|
+
catch (e) {
|
198
|
+
console.log((0, strip_indents_1.stripIndents) `
|
288
199
|
Unable to print terminal output for Task "${task.id}".
|
289
200
|
Task failed with Exit Code ${code} and Signal "${signal}".
|
290
201
|
|
291
202
|
Received error message:
|
292
203
|
${e.message}
|
293
204
|
`);
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
console.error(e);
|
303
|
-
rej(e);
|
304
|
-
}
|
305
|
-
});
|
306
|
-
}
|
307
|
-
readTerminalOutput(outputPath) {
|
308
|
-
return (0, fs_1.readFileSync)(outputPath).toString();
|
205
|
+
}
|
206
|
+
});
|
207
|
+
return cp;
|
208
|
+
}
|
209
|
+
catch (e) {
|
210
|
+
console.error(e);
|
211
|
+
throw e;
|
212
|
+
}
|
309
213
|
}
|
310
214
|
writeTerminalOutput(outputPath, content) {
|
311
215
|
(0, fs_1.writeFileSync)(outputPath, content);
|
@@ -318,12 +222,11 @@ class ForkedProcessTaskRunner {
|
|
318
222
|
}
|
319
223
|
// When the nx process gets a message, it will be sent into the task's process
|
320
224
|
process.on('message', (message) => {
|
321
|
-
// this.publisher.publish(message.toString());
|
322
225
|
if (this.pseudoTerminal) {
|
323
226
|
this.pseudoTerminal.sendMessageToChildren(message);
|
324
227
|
}
|
325
228
|
this.processes.forEach((p) => {
|
326
|
-
if ('
|
229
|
+
if ('send' in p) {
|
327
230
|
p.send(message);
|
328
231
|
}
|
329
232
|
});
|
@@ -331,34 +234,26 @@ class ForkedProcessTaskRunner {
|
|
331
234
|
// Terminate any task processes on exit
|
332
235
|
process.on('exit', () => {
|
333
236
|
this.processes.forEach((p) => {
|
334
|
-
|
335
|
-
p.kill();
|
336
|
-
}
|
237
|
+
p.kill();
|
337
238
|
});
|
338
239
|
});
|
339
240
|
process.on('SIGINT', () => {
|
340
241
|
this.processes.forEach((p) => {
|
341
|
-
|
342
|
-
p.kill('SIGTERM');
|
343
|
-
}
|
242
|
+
p.kill('SIGTERM');
|
344
243
|
});
|
345
244
|
// we exit here because we don't need to write anything to cache.
|
346
245
|
process.exit((0, exit_codes_1.signalToCode)('SIGINT'));
|
347
246
|
});
|
348
247
|
process.on('SIGTERM', () => {
|
349
248
|
this.processes.forEach((p) => {
|
350
|
-
|
351
|
-
p.kill('SIGTERM');
|
352
|
-
}
|
249
|
+
p.kill('SIGTERM');
|
353
250
|
});
|
354
251
|
// no exit here because we expect child processes to terminate which
|
355
252
|
// will store results to the cache and will terminate this process
|
356
253
|
});
|
357
254
|
process.on('SIGHUP', () => {
|
358
255
|
this.processes.forEach((p) => {
|
359
|
-
|
360
|
-
p.kill('SIGTERM');
|
361
|
-
}
|
256
|
+
p.kill('SIGTERM');
|
362
257
|
});
|
363
258
|
// no exit here because we expect child processes to terminate which
|
364
259
|
// will store results to the cache and will terminate this process
|
@@ -366,51 +261,3 @@ class ForkedProcessTaskRunner {
|
|
366
261
|
}
|
367
262
|
}
|
368
263
|
exports.ForkedProcessTaskRunner = ForkedProcessTaskRunner;
|
369
|
-
const colors = [
|
370
|
-
chalk.green,
|
371
|
-
chalk.greenBright,
|
372
|
-
chalk.red,
|
373
|
-
chalk.redBright,
|
374
|
-
chalk.cyan,
|
375
|
-
chalk.cyanBright,
|
376
|
-
chalk.yellow,
|
377
|
-
chalk.yellowBright,
|
378
|
-
chalk.magenta,
|
379
|
-
chalk.magentaBright,
|
380
|
-
];
|
381
|
-
function getColor(projectName) {
|
382
|
-
let code = 0;
|
383
|
-
for (let i = 0; i < projectName.length; ++i) {
|
384
|
-
code += projectName.charCodeAt(i);
|
385
|
-
}
|
386
|
-
const colorIndex = code % colors.length;
|
387
|
-
return colors[colorIndex];
|
388
|
-
}
|
389
|
-
/**
|
390
|
-
* Prevents terminal escape sequence from clearing line prefix.
|
391
|
-
*/
|
392
|
-
function logClearLineToPrefixTransformer(prefix) {
|
393
|
-
let prevChunk = null;
|
394
|
-
return new stream_1.Transform({
|
395
|
-
transform(chunk, _encoding, callback) {
|
396
|
-
if (prevChunk && prevChunk.toString() === '\x1b[2K') {
|
397
|
-
chunk = chunk.toString().replace(/\x1b\[1G/g, (m) => m + prefix);
|
398
|
-
}
|
399
|
-
this.push(chunk);
|
400
|
-
prevChunk = chunk;
|
401
|
-
callback();
|
402
|
-
},
|
403
|
-
});
|
404
|
-
}
|
405
|
-
function addPrefixTransformer(prefix) {
|
406
|
-
const newLineSeparator = process.platform.startsWith('win') ? '\r\n' : '\n';
|
407
|
-
return new stream_1.Transform({
|
408
|
-
transform(chunk, _encoding, callback) {
|
409
|
-
const list = chunk.toString().split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/g);
|
410
|
-
list
|
411
|
-
.filter(Boolean)
|
412
|
-
.forEach((m) => this.push(prefix ? prefix + ' ' + m + newLineSeparator : m + newLineSeparator));
|
413
|
-
callback();
|
414
|
-
},
|
415
|
-
});
|
416
|
-
}
|
@@ -36,6 +36,10 @@ async function initTasksRunner(nxArgs) {
|
|
36
36
|
acc[task.id] = [];
|
37
37
|
return acc;
|
38
38
|
}, {}),
|
39
|
+
continuousDependencies: opts.tasks.reduce((acc, task) => {
|
40
|
+
acc[task.id] = [];
|
41
|
+
return acc;
|
42
|
+
}, {}),
|
39
43
|
};
|
40
44
|
const taskResults = await (0, run_command_1.invokeTasksRunner)({
|
41
45
|
tasks: opts.tasks,
|
@@ -31,8 +31,14 @@ export declare class PseudoTerminal {
|
|
31
31
|
export declare class PseudoTtyProcess {
|
32
32
|
private childProcess;
|
33
33
|
isAlive: boolean;
|
34
|
-
exitCallbacks
|
34
|
+
private exitCallbacks;
|
35
|
+
private outputCallbacks;
|
36
|
+
private terminalOutput;
|
35
37
|
constructor(childProcess: ChildProcess);
|
38
|
+
getResults(): Promise<{
|
39
|
+
code: number;
|
40
|
+
terminalOutput: string;
|
41
|
+
}>;
|
36
42
|
onExit(callback: (code: number) => void): void;
|
37
43
|
onOutput(callback: (message: string) => void): void;
|
38
44
|
kill(): void;
|
@@ -78,28 +78,42 @@ class PseudoTtyProcess {
|
|
78
78
|
this.childProcess = childProcess;
|
79
79
|
this.isAlive = true;
|
80
80
|
this.exitCallbacks = [];
|
81
|
+
this.outputCallbacks = [];
|
82
|
+
this.terminalOutput = '';
|
83
|
+
childProcess.onOutput((output) => {
|
84
|
+
this.terminalOutput += output;
|
85
|
+
this.outputCallbacks.forEach((cb) => cb(output));
|
86
|
+
});
|
81
87
|
childProcess.onExit((message) => {
|
82
88
|
this.isAlive = false;
|
83
|
-
const
|
84
|
-
|
89
|
+
const code = messageToCode(message);
|
90
|
+
childProcess.cleanup();
|
91
|
+
this.exitCallbacks.forEach((cb) => cb(code));
|
92
|
+
});
|
93
|
+
}
|
94
|
+
async getResults() {
|
95
|
+
return new Promise((res) => {
|
96
|
+
this.onExit((code) => {
|
97
|
+
res({ code, terminalOutput: this.terminalOutput });
|
98
|
+
});
|
85
99
|
});
|
86
100
|
}
|
87
101
|
onExit(callback) {
|
88
102
|
this.exitCallbacks.push(callback);
|
89
103
|
}
|
90
104
|
onOutput(callback) {
|
91
|
-
this.
|
105
|
+
this.outputCallbacks.push(callback);
|
92
106
|
}
|
93
107
|
kill() {
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
108
|
+
if (this.isAlive) {
|
109
|
+
try {
|
110
|
+
this.childProcess.kill();
|
111
|
+
}
|
112
|
+
catch {
|
113
|
+
// when the child process completes before we explicitly call kill, this will throw
|
114
|
+
// do nothing
|
115
|
+
}
|
116
|
+
finally {
|
103
117
|
this.isAlive = false;
|
104
118
|
}
|
105
119
|
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { BatchResults } from '../batch/batch-messages';
|
2
|
+
import { ChildProcess, Serializable } from 'child_process';
|
3
|
+
export declare class BatchProcess {
|
4
|
+
private childProcess;
|
5
|
+
private executorName;
|
6
|
+
private exitCallbacks;
|
7
|
+
private resultsCallbacks;
|
8
|
+
constructor(childProcess: ChildProcess, executorName: string);
|
9
|
+
onExit(cb: (code: number) => void): void;
|
10
|
+
onResults(cb: (results: BatchResults) => void): void;
|
11
|
+
getResults(): Promise<BatchResults>;
|
12
|
+
send(message: Serializable): void;
|
13
|
+
kill(signal?: NodeJS.Signals | number): void;
|
14
|
+
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.BatchProcess = void 0;
|
4
|
+
const batch_messages_1 = require("../batch/batch-messages");
|
5
|
+
const exit_codes_1 = require("../../utils/exit-codes");
|
6
|
+
class BatchProcess {
|
7
|
+
constructor(childProcess, executorName) {
|
8
|
+
this.childProcess = childProcess;
|
9
|
+
this.executorName = executorName;
|
10
|
+
this.exitCallbacks = [];
|
11
|
+
this.resultsCallbacks = [];
|
12
|
+
this.childProcess.on('message', (message) => {
|
13
|
+
switch (message.type) {
|
14
|
+
case batch_messages_1.BatchMessageType.CompleteBatchExecution: {
|
15
|
+
for (const cb of this.resultsCallbacks) {
|
16
|
+
cb(message.results);
|
17
|
+
}
|
18
|
+
break;
|
19
|
+
}
|
20
|
+
case batch_messages_1.BatchMessageType.RunTasks: {
|
21
|
+
break;
|
22
|
+
}
|
23
|
+
default: {
|
24
|
+
// Re-emit any non-batch messages from the task process
|
25
|
+
if (process.send) {
|
26
|
+
process.send(message);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
});
|
31
|
+
this.childProcess.once('exit', (code, signal) => {
|
32
|
+
if (code === null)
|
33
|
+
code = (0, exit_codes_1.signalToCode)(signal);
|
34
|
+
for (const cb of this.exitCallbacks) {
|
35
|
+
cb(code);
|
36
|
+
}
|
37
|
+
});
|
38
|
+
}
|
39
|
+
onExit(cb) {
|
40
|
+
this.exitCallbacks.push(cb);
|
41
|
+
}
|
42
|
+
onResults(cb) {
|
43
|
+
this.resultsCallbacks.push(cb);
|
44
|
+
}
|
45
|
+
async getResults() {
|
46
|
+
return Promise.race([
|
47
|
+
new Promise((_, rej) => {
|
48
|
+
this.onExit((code) => {
|
49
|
+
if (code !== 0) {
|
50
|
+
rej(new Error(`"${this.executorName}" exited unexpectedly with code: ${code}`));
|
51
|
+
}
|
52
|
+
});
|
53
|
+
}),
|
54
|
+
new Promise((res) => {
|
55
|
+
this.onResults(res);
|
56
|
+
}),
|
57
|
+
]);
|
58
|
+
}
|
59
|
+
send(message) {
|
60
|
+
if (this.childProcess.connected) {
|
61
|
+
this.childProcess.send(message);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
kill(signal) {
|
65
|
+
if (this.childProcess.connected) {
|
66
|
+
this.childProcess.kill(signal);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
exports.BatchProcess = BatchProcess;
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { ChildProcess, Serializable } from 'child_process';
|
2
|
+
import { RunningTask } from './running-task';
|
3
|
+
export declare class NodeChildProcessWithNonDirectOutput implements RunningTask {
|
4
|
+
private childProcess;
|
5
|
+
private terminalOutput;
|
6
|
+
private exitCallbacks;
|
7
|
+
constructor(childProcess: ChildProcess, { streamOutput, prefix }: {
|
8
|
+
streamOutput: boolean;
|
9
|
+
prefix: string;
|
10
|
+
});
|
11
|
+
onExit(cb: (code: number, terminalOutput: string) => void): void;
|
12
|
+
getResults(): Promise<{
|
13
|
+
code: number;
|
14
|
+
terminalOutput: string;
|
15
|
+
}>;
|
16
|
+
send(message: Serializable): void;
|
17
|
+
kill(signal?: NodeJS.Signals | number): void;
|
18
|
+
}
|
19
|
+
export declare class NodeChildProcessWithDirectOutput implements RunningTask {
|
20
|
+
private childProcess;
|
21
|
+
private temporaryOutputPath;
|
22
|
+
private terminalOutput;
|
23
|
+
private exitCallbacks;
|
24
|
+
private exited;
|
25
|
+
private exitCode;
|
26
|
+
constructor(childProcess: ChildProcess, temporaryOutputPath: string);
|
27
|
+
send(message: Serializable): void;
|
28
|
+
onExit(cb: (code: number, signal: NodeJS.Signals) => void): void;
|
29
|
+
getResults(): Promise<{
|
30
|
+
code: number;
|
31
|
+
terminalOutput: string;
|
32
|
+
}>;
|
33
|
+
waitForExit(): Promise<void>;
|
34
|
+
getTerminalOutput(): string;
|
35
|
+
kill(signal?: NodeJS.Signals | number): void;
|
36
|
+
}
|