nx 20.8.0-rc.0 → 20.8.1
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 +11 -11
- package/src/command-line/init/configure-plugins.js +5 -3
- package/src/command-line/init/implementation/utils.d.ts +2 -1
- package/src/command-line/init/implementation/utils.js +2 -1
- package/src/command-line/init/init-v2.js +8 -7
- package/src/core/graph/main.js +1 -1
- package/src/native/index.js +16 -2
- package/src/native/nx.wasm32-wasi.wasm +0 -0
- package/src/tasks-runner/forked-process-task-runner.d.ts +2 -0
- package/src/tasks-runner/forked-process-task-runner.js +44 -34
- package/src/tasks-runner/task-orchestrator.js +1 -0
- package/src/tasks-runner/utils.js +2 -0
package/src/native/index.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
const { join, basename } = require('path');
|
2
|
-
const { copyFileSync, existsSync, mkdirSync } = require('fs');
|
2
|
+
const { copyFileSync, existsSync, mkdirSync, renameSync } = require('fs');
|
3
3
|
const Module = require('module');
|
4
4
|
const { nxVersion } = require('../utils/versions');
|
5
5
|
const { getNativeFileCacheLocation } = require('./native-file-cache-location');
|
@@ -71,14 +71,28 @@ Module._load = function (request, parent, isMain) {
|
|
71
71
|
|
72
72
|
// we copy the file to a workspace-scoped tmp directory and prefix with nxVersion to avoid stale files being loaded
|
73
73
|
const nativeFileCacheLocation = getNativeFileCacheLocation();
|
74
|
+
// This is a path to copy to, not the one that gets loaded
|
75
|
+
const tmpTmpFile = join(
|
76
|
+
nativeFileCacheLocation,
|
77
|
+
nxVersion + '-' + Math.random() + fileName
|
78
|
+
);
|
79
|
+
// This is the path that will get loaded
|
74
80
|
const tmpFile = join(nativeFileCacheLocation, nxVersion + '-' + fileName);
|
81
|
+
|
82
|
+
// If the file to be loaded already exists, just load it
|
75
83
|
if (existsSync(tmpFile)) {
|
76
84
|
return originalLoad.apply(this, [tmpFile, parent, isMain]);
|
77
85
|
}
|
78
86
|
if (!existsSync(nativeFileCacheLocation)) {
|
79
87
|
mkdirSync(nativeFileCacheLocation, { recursive: true });
|
80
88
|
}
|
81
|
-
|
89
|
+
// First copy to a unique location for each process
|
90
|
+
copyFileSync(nativeLocation, tmpTmpFile);
|
91
|
+
|
92
|
+
// Then rename to the final location
|
93
|
+
renameSync(tmpTmpFile, tmpFile);
|
94
|
+
|
95
|
+
// Load from the final location
|
82
96
|
return originalLoad.apply(this, [tmpFile, parent, isMain]);
|
83
97
|
} else {
|
84
98
|
// call the original _load function for everything else
|
Binary file
|
@@ -8,10 +8,12 @@ export declare class ForkedProcessTaskRunner {
|
|
8
8
|
cliPath: string;
|
9
9
|
private readonly verbose;
|
10
10
|
private processes;
|
11
|
+
private finishedProcesses;
|
11
12
|
private pseudoTerminal;
|
12
13
|
constructor(options: DefaultTasksRunnerOptions);
|
13
14
|
init(): Promise<void>;
|
14
15
|
forkProcessForBatch({ executorName, taskGraph: batchTaskGraph }: Batch, projectGraph: ProjectGraph, fullTaskGraph: TaskGraph, env: NodeJS.ProcessEnv): Promise<BatchResults>;
|
16
|
+
cleanUpBatchProcesses(): void;
|
15
17
|
forkProcessLegacy(task: Task, { temporaryOutputPath, streamOutput, pipeOutput, taskGraph, env, }: {
|
16
18
|
temporaryOutputPath: string;
|
17
19
|
streamOutput: boolean;
|
@@ -20,6 +20,7 @@ class ForkedProcessTaskRunner {
|
|
20
20
|
this.cliPath = (0, utils_1.getCliPath)();
|
21
21
|
this.verbose = process.env.NX_VERBOSE_LOGGING === 'true';
|
22
22
|
this.processes = new Set();
|
23
|
+
this.finishedProcesses = new Set();
|
23
24
|
this.pseudoTerminal = pseudo_terminal_1.PseudoTerminal.isSupported()
|
24
25
|
? (0, pseudo_terminal_1.getPseudoTerminal)()
|
25
26
|
: null;
|
@@ -33,6 +34,7 @@ class ForkedProcessTaskRunner {
|
|
33
34
|
// TODO: vsavkin delegate terminal output printing
|
34
35
|
forkProcessForBatch({ executorName, taskGraph: batchTaskGraph }, projectGraph, fullTaskGraph, env) {
|
35
36
|
return new Promise((res, rej) => {
|
37
|
+
let p;
|
36
38
|
try {
|
37
39
|
const count = Object.keys(batchTaskGraph.tasks).length;
|
38
40
|
if (count > 1) {
|
@@ -42,7 +44,7 @@ class ForkedProcessTaskRunner {
|
|
42
44
|
const args = (0, utils_1.getPrintableCommandArgsForTask)(Object.values(batchTaskGraph.tasks)[0]);
|
43
45
|
output_1.output.logCommand(args.join(' '));
|
44
46
|
}
|
45
|
-
|
47
|
+
p = (0, child_process_1.fork)(workerPath, {
|
46
48
|
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
47
49
|
env,
|
48
50
|
});
|
@@ -52,20 +54,18 @@ class ForkedProcessTaskRunner {
|
|
52
54
|
if (code === null)
|
53
55
|
code = (0, exit_codes_1.signalToCode)(signal);
|
54
56
|
if (code !== 0) {
|
55
|
-
const results = {};
|
56
|
-
for (const rootTaskId of batchTaskGraph.roots) {
|
57
|
-
results[rootTaskId] = {
|
58
|
-
success: false,
|
59
|
-
terminalOutput: '',
|
60
|
-
};
|
61
|
-
}
|
62
57
|
rej(new Error(`"${executorName}" exited unexpectedly with code: ${code}`));
|
63
58
|
}
|
64
59
|
});
|
60
|
+
p.on('error', (err) => {
|
61
|
+
this.processes.delete(p);
|
62
|
+
rej(err || new Error(`"${executorName}" exited unexpectedly`));
|
63
|
+
});
|
65
64
|
p.on('message', (message) => {
|
66
65
|
switch (message.type) {
|
67
66
|
case batch_messages_1.BatchMessageType.CompleteBatchExecution: {
|
68
67
|
res(message.results);
|
68
|
+
this.finishedProcesses.add(p);
|
69
69
|
break;
|
70
70
|
}
|
71
71
|
case batch_messages_1.BatchMessageType.RunTasks: {
|
@@ -90,9 +90,23 @@ class ForkedProcessTaskRunner {
|
|
90
90
|
}
|
91
91
|
catch (e) {
|
92
92
|
rej(e);
|
93
|
+
if (p) {
|
94
|
+
this.processes.delete(p);
|
95
|
+
p.kill();
|
96
|
+
}
|
93
97
|
}
|
94
98
|
});
|
95
99
|
}
|
100
|
+
cleanUpBatchProcesses() {
|
101
|
+
if (this.finishedProcesses.size > 0) {
|
102
|
+
this.finishedProcesses.forEach((p) => {
|
103
|
+
if ('connected' in p ? p.connected : p.isAlive) {
|
104
|
+
p.kill();
|
105
|
+
}
|
106
|
+
});
|
107
|
+
this.finishedProcesses.clear();
|
108
|
+
}
|
109
|
+
}
|
96
110
|
async forkProcessLegacy(task, { temporaryOutputPath, streamOutput, pipeOutput, taskGraph, env, }) {
|
97
111
|
return pipeOutput
|
98
112
|
? await this.forkProcessPipeOutputCapture(task, {
|
@@ -157,6 +171,7 @@ class ForkedProcessTaskRunner {
|
|
157
171
|
});
|
158
172
|
return new Promise((res) => {
|
159
173
|
p.onExit((code) => {
|
174
|
+
this.processes.delete(p);
|
160
175
|
// If the exit code is greater than 128, it's a special exit code for a signal
|
161
176
|
if (code >= 128) {
|
162
177
|
process.exit(code);
|
@@ -227,7 +242,7 @@ class ForkedProcessTaskRunner {
|
|
227
242
|
p.stderr.on('data', (chunk) => {
|
228
243
|
outWithErr.push(chunk.toString());
|
229
244
|
});
|
230
|
-
p.
|
245
|
+
p.once('exit', (code, signal) => {
|
231
246
|
this.processes.delete(p);
|
232
247
|
if (code === null)
|
233
248
|
code = (0, exit_codes_1.signalToCode)(signal);
|
@@ -272,7 +287,8 @@ class ForkedProcessTaskRunner {
|
|
272
287
|
taskGraph,
|
273
288
|
isVerbose: this.verbose,
|
274
289
|
});
|
275
|
-
p.
|
290
|
+
p.once('exit', (code, signal) => {
|
291
|
+
this.processes.delete(p);
|
276
292
|
if (code === null)
|
277
293
|
code = (0, exit_codes_1.signalToCode)(signal);
|
278
294
|
// we didn't print any output as we were running the command
|
@@ -317,8 +333,7 @@ class ForkedProcessTaskRunner {
|
|
317
333
|
process.send(message);
|
318
334
|
});
|
319
335
|
}
|
320
|
-
|
321
|
-
process.on('message', (message) => {
|
336
|
+
const messageHandler = (message) => {
|
322
337
|
// this.publisher.publish(message.toString());
|
323
338
|
if (this.pseudoTerminal) {
|
324
339
|
this.pseudoTerminal.sendMessageToChildren(message);
|
@@ -328,39 +343,34 @@ class ForkedProcessTaskRunner {
|
|
328
343
|
p.send(message);
|
329
344
|
}
|
330
345
|
});
|
331
|
-
}
|
332
|
-
//
|
333
|
-
process.on('
|
346
|
+
};
|
347
|
+
// When the nx process gets a message, it will be sent into the task's process
|
348
|
+
process.on('message', messageHandler);
|
349
|
+
const cleanUp = (signal) => {
|
334
350
|
this.processes.forEach((p) => {
|
335
351
|
if ('connected' in p ? p.connected : p.isAlive) {
|
336
|
-
p.kill();
|
352
|
+
p.kill(signal);
|
337
353
|
}
|
338
354
|
});
|
355
|
+
process.off('message', messageHandler);
|
356
|
+
this.cleanUpBatchProcesses();
|
357
|
+
};
|
358
|
+
// Terminate any task processes on exit
|
359
|
+
process.once('exit', () => {
|
360
|
+
cleanUp();
|
339
361
|
});
|
340
|
-
process.
|
341
|
-
|
342
|
-
if ('connected' in p ? p.connected : p.isAlive) {
|
343
|
-
p.kill('SIGTERM');
|
344
|
-
}
|
345
|
-
});
|
362
|
+
process.once('SIGINT', () => {
|
363
|
+
cleanUp('SIGTERM');
|
346
364
|
// we exit here because we don't need to write anything to cache.
|
347
365
|
process.exit((0, exit_codes_1.signalToCode)('SIGINT'));
|
348
366
|
});
|
349
|
-
process.
|
350
|
-
|
351
|
-
if ('connected' in p ? p.connected : p.isAlive) {
|
352
|
-
p.kill('SIGTERM');
|
353
|
-
}
|
354
|
-
});
|
367
|
+
process.once('SIGTERM', () => {
|
368
|
+
cleanUp('SIGTERM');
|
355
369
|
// no exit here because we expect child processes to terminate which
|
356
370
|
// will store results to the cache and will terminate this process
|
357
371
|
});
|
358
|
-
process.
|
359
|
-
|
360
|
-
if ('connected' in p ? p.connected : p.isAlive) {
|
361
|
-
p.kill('SIGTERM');
|
362
|
-
}
|
363
|
-
});
|
372
|
+
process.once('SIGHUP', () => {
|
373
|
+
cleanUp('SIGTERM');
|
364
374
|
// no exit here because we expect child processes to terminate which
|
365
375
|
// will store results to the cache and will terminate this process
|
366
376
|
});
|
@@ -171,6 +171,7 @@ class TaskOrchestrator {
|
|
171
171
|
results.push(...batchResults);
|
172
172
|
}
|
173
173
|
await this.postRunSteps(tasks, results, doNotSkipCache, { groupId });
|
174
|
+
this.forkedProcessTaskRunner.cleanUpBatchProcesses();
|
174
175
|
const tasksCompleted = taskEntries.filter(([taskId]) => this.completedTasks[taskId]);
|
175
176
|
// Batch is still not done, run it again
|
176
177
|
if (tasksCompleted.length !== taskEntries.length) {
|
@@ -362,6 +362,8 @@ function getSerializedArgsForTask(task, isVerbose) {
|
|
362
362
|
function shouldStreamOutput(task, initiatingProject) {
|
363
363
|
if (process.env.NX_STREAM_OUTPUT === 'true')
|
364
364
|
return true;
|
365
|
+
if (process.env.NX_STREAM_OUTPUT === 'false')
|
366
|
+
return false;
|
365
367
|
if (longRunningTask(task))
|
366
368
|
return true;
|
367
369
|
if (task.target.project === initiatingProject)
|