nx 23.3.0-beta.0 → 23.3.0-beta.2
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/dist/src/command-line/format/format.js +2 -18
- package/dist/src/command-line/graph/graph.js +42 -3
- package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +0 -3
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +0 -3
- package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +0 -3
- package/dist/src/command-line/init/implementation/angular/index.js +0 -3
- package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +0 -3
- package/dist/src/command-line/init/implementation/format.js +2 -3
- package/dist/src/command-line/init/implementation/utils.d.ts +0 -1
- package/dist/src/command-line/init/implementation/utils.js +0 -8
- package/dist/src/command-line/init/init-v2.js +0 -3
- package/dist/src/command-line/migrate/agentic/definitions.js +75 -19
- package/dist/src/command-line/migrate/agentic/format-command.d.ts +14 -0
- package/dist/src/command-line/migrate/agentic/format-command.js +44 -0
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.d.ts +3 -3
- package/dist/src/command-line/migrate/agentic/handoff-gitignore.js +3 -3
- package/dist/src/command-line/migrate/agentic/handoff.d.ts +27 -17
- package/dist/src/command-line/migrate/agentic/handoff.js +107 -24
- package/dist/src/command-line/migrate/agentic/instruction-files.d.ts +21 -0
- package/dist/src/command-line/migrate/agentic/instruction-files.js +36 -0
- package/dist/src/command-line/migrate/agentic/prompts/fragments.d.ts +16 -0
- package/dist/src/command-line/migrate/agentic/prompts/fragments.js +70 -0
- package/dist/src/command-line/migrate/agentic/prompts/generic-validation.js +4 -3
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.d.ts +25 -1
- package/dist/src/command-line/migrate/agentic/prompts/system-prompt.js +57 -34
- package/dist/src/command-line/migrate/agentic/run-step.js +28 -4
- package/dist/src/command-line/migrate/agentic/runner.d.ts +17 -8
- package/dist/src/command-line/migrate/agentic/runner.js +110 -55
- package/dist/src/command-line/migrate/agentic/types.d.ts +23 -8
- package/dist/src/command-line/migrate/agentic/types.js +10 -7
- package/dist/src/command-line/migrate/migrate-commits.d.ts +1 -0
- package/dist/src/command-line/migrate/migrate-commits.js +9 -0
- package/dist/src/command-line/migrate/migrate-output.d.ts +3 -7
- package/dist/src/command-line/migrate/migrate-output.js +3 -7
- package/dist/src/command-line/migrate/migrate.js +21 -8
- package/dist/src/command-line/migrate/run/agent-output.d.ts +10 -0
- package/dist/src/command-line/migrate/run/agent-output.js +16 -2
- package/dist/src/command-line/migrate/run/agent-work-payload.d.ts +37 -0
- package/dist/src/command-line/migrate/run/agent-work-payload.js +142 -0
- package/dist/src/command-line/migrate/run/atomic-write.d.ts +8 -0
- package/dist/src/command-line/migrate/run/atomic-write.js +17 -0
- package/dist/src/command-line/migrate/run/index.d.ts +1 -1
- package/dist/src/command-line/migrate/run/issues.d.ts +106 -0
- package/dist/src/command-line/migrate/run/issues.js +980 -0
- package/dist/src/command-line/migrate/run/orchestrator.d.ts +1 -0
- package/dist/src/command-line/migrate/run/orchestrator.js +662 -105
- package/dist/src/command-line/migrate/run/run-state.d.ts +43 -8
- package/dist/src/command-line/migrate/run/run-state.js +184 -20
- package/dist/src/command-line/migrate/run/runbook.d.ts +17 -0
- package/dist/src/command-line/migrate/run/runbook.js +97 -0
- package/dist/src/command-line/migrate/run/state-lock.d.ts +2 -2
- package/dist/src/command-line/migrate/run/state-lock.js +2 -2
- package/dist/src/command-line/migrate/run/state-machine.d.ts +5 -1
- package/dist/src/command-line/migrate/run/state-machine.js +27 -1
- package/dist/src/command-line/migrate/run/worker.js +206 -56
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +5 -11
- package/dist/src/command-line/release/publish.js +11 -4
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +3 -3
- package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +3 -3
- package/dist/src/command-line/release/utils/remote-release-clients/remote-release-client.d.ts +2 -0
- package/dist/src/command-line/release/utils/remote-release-clients/remote-release-client.js +35 -0
- package/dist/src/command-line/report/report.d.ts +2 -0
- package/dist/src/command-line/report/report.js +28 -1
- package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
- package/dist/src/command-line/yargs-utils/shared-options.js +22 -4
- package/dist/src/config/workspace-json-project-json.d.ts +2 -0
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/daemon/client/client.d.ts +6 -2
- package/dist/src/daemon/client/client.js +27 -11
- package/dist/src/daemon/message-types/get-plugin-capabilities.d.ts +5 -0
- package/dist/src/daemon/message-types/get-plugin-capabilities.js +11 -0
- package/dist/src/daemon/message-types/run-tasks-execution-hooks.d.ts +3 -2
- package/dist/src/daemon/server/handle-get-plugin-capabilities.d.ts +2 -0
- package/dist/src/daemon/server/handle-get-plugin-capabilities.js +13 -0
- package/dist/src/daemon/server/handle-hash-tasks.d.ts +8 -2
- package/dist/src/daemon/server/handle-hash-tasks.js +16 -3
- package/dist/src/daemon/server/handle-outputs-changes.d.ts +2 -2
- package/dist/src/daemon/server/handle-outputs-changes.js +21 -6
- package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +3 -2
- package/dist/src/daemon/server/outputs-tracking.d.ts +6 -0
- package/dist/src/daemon/server/outputs-tracking.js +18 -0
- package/dist/src/daemon/server/project-graph-incremental-recomputation.d.ts +22 -7
- package/dist/src/daemon/server/project-graph-incremental-recomputation.js +100 -70
- package/dist/src/daemon/server/restart-checks.d.ts +22 -0
- package/dist/src/daemon/server/restart-checks.js +77 -0
- package/dist/src/daemon/server/server.js +33 -18
- package/dist/src/daemon/server/shutdown-utils.d.ts +0 -5
- package/dist/src/daemon/server/shutdown-utils.js +3 -26
- package/dist/src/hasher/hash-task.js +20 -16
- package/dist/src/hasher/native-task-hasher-impl.d.ts +8 -0
- package/dist/src/hasher/native-task-hasher-impl.js +46 -3
- package/dist/src/hasher/task-hasher.d.ts +9 -0
- package/dist/src/hasher/task-hasher.js +14 -0
- package/dist/src/native/index.d.ts +222 -21
- package/dist/src/native/index.js +3 -3
- package/dist/src/native/native-bindings.js +4 -1
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +1 -1
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.d.ts +2 -0
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +22 -0
- package/dist/src/plugins/js/utils/register.js +2 -1
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +19 -26
- package/dist/src/project-graph/error-types.d.ts +5 -0
- package/dist/src/project-graph/error-types.js +44 -5
- package/dist/src/project-graph/file-utils.d.ts +2 -0
- package/dist/src/project-graph/file-utils.js +6 -1
- package/dist/src/project-graph/nx-deps-cache.d.ts +5 -2
- package/dist/src/project-graph/nx-deps-cache.js +4 -4
- package/dist/src/project-graph/plugins/get-plugins.d.ts +3 -1
- package/dist/src/project-graph/plugins/get-plugins.js +60 -82
- package/dist/src/project-graph/plugins/in-process-loader.d.ts +1 -1
- package/dist/src/project-graph/plugins/in-process-loader.js +1 -4
- package/dist/src/project-graph/plugins/isolation/index.d.ts +1 -1
- package/dist/src/project-graph/plugins/isolation/index.js +3 -1
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +8 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +42 -6
- package/dist/src/project-graph/plugins/isolation/load-isolated-plugin.d.ts +10 -1
- package/dist/src/project-graph/plugins/isolation/load-isolated-plugin.js +67 -17
- package/dist/src/project-graph/plugins/isolation/messaging.d.ts +3 -2
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +5 -1
- package/dist/src/project-graph/plugins/loaded-nx-plugin.d.ts +5 -2
- package/dist/src/project-graph/plugins/loaded-nx-plugin.js +14 -1
- package/dist/src/project-graph/plugins/nx-plugin-capabilities.d.ts +6 -0
- package/dist/src/project-graph/plugins/nx-plugin-capabilities.js +28 -0
- package/dist/src/project-graph/plugins/task-results-stub.d.ts +50 -0
- package/dist/src/project-graph/plugins/task-results-stub.js +111 -0
- package/dist/src/project-graph/plugins/tasks-execution-hooks.d.ts +3 -2
- package/dist/src/project-graph/plugins/tasks-execution-hooks.js +14 -1
- package/dist/src/project-graph/project-graph.js +43 -42
- package/dist/src/tasks-runner/batch/run-batch.js +15 -0
- package/dist/src/tasks-runner/cache.d.ts +35 -0
- package/dist/src/tasks-runner/cache.js +40 -0
- package/dist/src/tasks-runner/create-task-graph.js +1 -0
- package/dist/src/tasks-runner/default-tasks-runner.js +1 -1
- package/dist/src/tasks-runner/forked-process-task-runner.d.ts +1 -1
- package/dist/src/tasks-runner/forked-process-task-runner.js +8 -7
- package/dist/src/tasks-runner/init-tasks-runner.js +5 -1
- package/dist/src/tasks-runner/is-tui-enabled.js +4 -3
- package/dist/src/tasks-runner/life-cycle.d.ts +7 -0
- package/dist/src/tasks-runner/life-cycle.js +7 -0
- package/dist/src/tasks-runner/life-cycles/summary-terminal-output-life-cycle.d.ts +35 -0
- package/dist/src/tasks-runner/life-cycles/summary-terminal-output-life-cycle.js +146 -0
- package/dist/src/tasks-runner/prune-task-graph.d.ts +17 -0
- package/dist/src/tasks-runner/prune-task-graph.js +45 -0
- package/dist/src/tasks-runner/run-command.js +14 -3
- package/dist/src/tasks-runner/running-tasks/batch-process.d.ts +93 -19
- package/dist/src/tasks-runner/running-tasks/batch-process.js +184 -88
- package/dist/src/tasks-runner/task-orchestrator.d.ts +64 -2
- package/dist/src/tasks-runner/task-orchestrator.js +232 -46
- package/dist/src/tasks-runner/terminal-output-path.d.ts +11 -0
- package/dist/src/tasks-runner/terminal-output-path.js +18 -0
- package/dist/src/tasks-runner/utils.js +5 -2
- package/dist/src/utils/ab-testing.d.ts +4 -1
- package/dist/src/utils/ab-testing.js +11 -7
- package/dist/src/utils/chunkify.d.ts +1 -7
- package/dist/src/utils/chunkify.js +2 -8
- package/dist/src/utils/command-line-utils.d.ts +19 -0
- package/dist/src/utils/command-line-utils.js +10 -3
- package/dist/src/utils/formatters/index.d.ts +6 -0
- package/dist/src/utils/formatters/index.js +5 -0
- package/dist/src/utils/formatters/prettier.d.ts +0 -8
- package/dist/src/utils/formatters/prettier.js +4 -26
- package/dist/src/utils/handle-errors.js +5 -43
- package/dist/src/utils/installed-nx-version.js +2 -48
- package/dist/src/utils/min-release-age/packument.js +1 -1
- package/dist/src/utils/output.d.ts +22 -3
- package/dist/src/utils/output.js +28 -5
- package/dist/src/utils/package-json.d.ts +25 -0
- package/dist/src/utils/package-json.js +41 -6
- package/dist/src/utils/package-manager.d.ts +6 -0
- package/dist/src/utils/package-manager.js +10 -0
- package/dist/src/utils/plugins/plugin-capabilities.js +7 -2
- package/dist/src/utils/provenance.js +20 -4
- package/dist/src/utils/serialize-overrides-into-command-line.js +2 -4
- package/dist/src/utils/workspace-context.d.ts +47 -3
- package/dist/src/utils/workspace-context.js +162 -10
- package/package.json +12 -13
- package/schemas/nx-schema.json +4 -0
- package/schemas/project-schema.json +4 -0
- package/dist/src/daemon/server/file-watching/route-workspace-changes.d.ts +0 -9
- package/dist/src/daemon/server/file-watching/route-workspace-changes.js +0 -76
- package/dist/src/daemon/server/watcher.d.ts +0 -18
- package/dist/src/daemon/server/watcher.js +0 -126
|
@@ -2,32 +2,72 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BatchProcess = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
5
6
|
const path_1 = require("path");
|
|
6
7
|
const native_1 = require("../../native");
|
|
7
|
-
const
|
|
8
|
+
const cache_1 = require("../cache");
|
|
8
9
|
const exit_codes_1 = require("../../utils/exit-codes");
|
|
9
10
|
const output_1 = require("../../utils/output");
|
|
10
11
|
const batch_messages_1 = require("../batch/batch-messages");
|
|
11
12
|
class BatchProcess {
|
|
12
|
-
constructor(childProcess, executorName
|
|
13
|
+
constructor(childProcess, executorName,
|
|
14
|
+
/**
|
|
15
|
+
* Whether the active output style puts task bytes on the terminal at all.
|
|
16
|
+
* `summary` does not, and its life cycle cannot enforce that here: this
|
|
17
|
+
* class writes to `output` directly from a stream handler, so without being
|
|
18
|
+
* told it would print a whole batch into a run that asked for log paths.
|
|
19
|
+
*
|
|
20
|
+
* False makes this capture rather than print. Suppressing the write alone
|
|
21
|
+
* would drop the bytes entirely off GitHub Actions, where nothing else
|
|
22
|
+
* captures them - and the worker's own crash output is exactly what no task
|
|
23
|
+
* ever claims, so it would exist nowhere.
|
|
24
|
+
*/
|
|
25
|
+
printsOutput = true,
|
|
26
|
+
/** Labels the capture file so it is identifiable in `batchOutputs/`. */
|
|
27
|
+
batchId = executorName) {
|
|
13
28
|
this.childProcess = childProcess;
|
|
14
29
|
this.executorName = executorName;
|
|
30
|
+
this.printsOutput = printsOutput;
|
|
31
|
+
this.batchId = batchId;
|
|
15
32
|
this.exitCallbacks = [];
|
|
16
33
|
this.batchResultsCallbacks = [];
|
|
17
34
|
this.taskResultsCallbacks = [];
|
|
18
35
|
this.outputCallbacks = [];
|
|
36
|
+
/** Sources paused for backpressure, awaiting a 'drain' that may never come. */
|
|
37
|
+
this.pausedSources = new Set();
|
|
19
38
|
/**
|
|
20
39
|
* Set once the capture is released. A chunk can still arrive after that —
|
|
21
|
-
* stdout delivers past the exit event — and
|
|
22
|
-
*
|
|
40
|
+
* stdout delivers past the exit event — and writing then would reach a file
|
|
41
|
+
* the renderer has already read.
|
|
23
42
|
*/
|
|
24
43
|
this.capturedOutputDiscarded = false;
|
|
25
44
|
/**
|
|
26
|
-
* Set when
|
|
27
|
-
*
|
|
28
|
-
*
|
|
45
|
+
* Set when the capture file could not be written. Whatever reached it is kept
|
|
46
|
+
* and still rendered: that is the head of the batch's log, where a compiler's
|
|
47
|
+
* first non-cascading errors are. Everything after it goes to the terminal -
|
|
48
|
+
* see `capture`.
|
|
29
49
|
*/
|
|
30
50
|
this.capturedOutputFailed = false;
|
|
51
|
+
/** Set once the failure has been reported, so it is said once per batch. */
|
|
52
|
+
this.capturedOutputWarned = false;
|
|
53
|
+
/** Set before `end()`: a write after it would destroy the unflushed tail. */
|
|
54
|
+
this.capturedOutputClosing = false;
|
|
55
|
+
/**
|
|
56
|
+
* Makes the capture file unique across every batch in the process, which
|
|
57
|
+
* `batchId` alone does not: `TasksSchedule.batchCounters` is per instance, so
|
|
58
|
+
* a second orchestrator in the same process - `runDiscreteTasks` and
|
|
59
|
+
* `runContinuousTasks`, not the CLI - re-mints `<executor> 1`, and the pid
|
|
60
|
+
* cannot separate them.
|
|
61
|
+
*/
|
|
62
|
+
this.captureSeq = ++BatchProcess.captureSeq;
|
|
63
|
+
/**
|
|
64
|
+
* Separates this capture from one minted by a DIFFERENT process, which
|
|
65
|
+
* `captureSeq` cannot: it is a per-process static that restarts at 1. These
|
|
66
|
+
* files now outlive their batch and `cacheDir` can be shared across checkouts
|
|
67
|
+
* of a repo, so without this a recycled pid truncates a log an earlier run's
|
|
68
|
+
* summary is still pointing at.
|
|
69
|
+
*/
|
|
70
|
+
this.captureNonce = (0, crypto_1.randomBytes)(4).toString('hex');
|
|
31
71
|
this.childProcess.on('message', (message) => {
|
|
32
72
|
switch (message.type) {
|
|
33
73
|
case batch_messages_1.BatchMessageType.CompleteTask: {
|
|
@@ -70,8 +110,8 @@ class BatchProcess {
|
|
|
70
110
|
// current terminal output behavior. These chunks are forwarded raw and
|
|
71
111
|
// routinely end mid-line, so they go through `output` to keep its line
|
|
72
112
|
// tracking accurate for whatever prints next.
|
|
73
|
-
if ((0, output_1.shouldGroupBatchOutput)()) {
|
|
74
|
-
this.capture(chunk);
|
|
113
|
+
if ((0, output_1.shouldGroupBatchOutput)() || !this.printsOutput) {
|
|
114
|
+
this.capture(chunk, this.childProcess.stdout);
|
|
75
115
|
}
|
|
76
116
|
else {
|
|
77
117
|
output_1.output.writeTaskOutputChunk(chunk);
|
|
@@ -86,8 +126,8 @@ class BatchProcess {
|
|
|
86
126
|
if (this.childProcess.stderr) {
|
|
87
127
|
this.childProcess.stderr.on('data', (chunk) => {
|
|
88
128
|
const text = chunk.toString();
|
|
89
|
-
if ((0, output_1.shouldGroupBatchOutput)()) {
|
|
90
|
-
this.capture(chunk,
|
|
129
|
+
if ((0, output_1.shouldGroupBatchOutput)() || !this.printsOutput) {
|
|
130
|
+
this.capture(chunk, this.childProcess.stderr);
|
|
91
131
|
}
|
|
92
132
|
else {
|
|
93
133
|
// Maintain current terminal output behavior
|
|
@@ -112,88 +152,144 @@ class BatchProcess {
|
|
|
112
152
|
onOutput(cb) {
|
|
113
153
|
this.outputCallbacks.push(cb);
|
|
114
154
|
}
|
|
115
|
-
capture(chunk,
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
if (this.capturedOutputDiscarded) {
|
|
155
|
+
capture(chunk, source) {
|
|
156
|
+
// A closed or released capture drops the chunk; see `getCapturedOutputPath`.
|
|
157
|
+
if (this.capturedOutputDiscarded || this.capturedOutputClosing) {
|
|
119
158
|
return;
|
|
120
159
|
}
|
|
160
|
+
// A failed one does not. The style withheld these bytes on the promise that
|
|
161
|
+
// they are readable elsewhere; once the file is unwritable that promise
|
|
162
|
+
// cannot be kept, so they go to the terminal even under a style that prints
|
|
163
|
+
// nothing. Losing the format is survivable, losing task output is what this
|
|
164
|
+
// path exists to prevent.
|
|
121
165
|
if (this.capturedOutputFailed) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
166
|
+
this.forwardUncaptured(chunk, source);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const stream = this.openCapturedOutput();
|
|
170
|
+
if (!stream) {
|
|
171
|
+
// Opening is what failed, so nothing of this chunk reached disk.
|
|
172
|
+
this.forwardUncaptured(chunk, source);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
// A full write buffer pauses the worker rather than growing in this
|
|
176
|
+
// process. Tracked, because only 'drain' resumes it and a stream that
|
|
177
|
+
// errors never emits one - see `resumeCapturedSources`.
|
|
178
|
+
if (!stream.write(chunk) && source) {
|
|
179
|
+
this.pausedSources.add(source);
|
|
180
|
+
source.pause();
|
|
181
|
+
stream.once('drain', () => {
|
|
182
|
+
this.pausedSources.delete(source);
|
|
183
|
+
source.resume();
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Puts bytes the capture could not take back on the terminal, on the stream
|
|
189
|
+
* they arrived on.
|
|
190
|
+
*/
|
|
191
|
+
forwardUncaptured(chunk, source) {
|
|
192
|
+
output_1.output.writeTaskOutputChunk(chunk, source === this.childProcess.stderr ? process.stderr : process.stdout);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Names the failure once. A stream reports it asynchronously, so the chunk
|
|
196
|
+
* that tripped it may or may not have reached disk - unlike a `writeSync`,
|
|
197
|
+
* there is no byte count to tell. Every chunk after it is forwarded.
|
|
198
|
+
*/
|
|
199
|
+
warnCaptureFailed(reason) {
|
|
200
|
+
if (this.capturedOutputWarned) {
|
|
125
201
|
return;
|
|
126
202
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
203
|
+
this.capturedOutputWarned = true;
|
|
204
|
+
output_1.output.warn({
|
|
205
|
+
title: `Could not capture batch output for ${this.executorName}`,
|
|
206
|
+
bodyLines: [reason, 'Streaming the rest of it live instead.'],
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Lets the worker write again after the capture has stopped.
|
|
211
|
+
*
|
|
212
|
+
* Without this a failed capture wedges the whole run: the source stays
|
|
213
|
+
* paused, so the worker blocks once its stdout pipe fills, never sends its
|
|
214
|
+
* results, and `getResults` waits on a batch that can no longer finish.
|
|
215
|
+
*/
|
|
216
|
+
resumeCapturedSources() {
|
|
217
|
+
const resumed = [...this.pausedSources];
|
|
218
|
+
for (const source of resumed) {
|
|
219
|
+
source.resume();
|
|
220
|
+
}
|
|
221
|
+
this.pausedSources.clear();
|
|
222
|
+
return resumed;
|
|
223
|
+
}
|
|
224
|
+
openCapturedOutput() {
|
|
225
|
+
if (this.capturedOutputStream) {
|
|
226
|
+
return this.capturedOutputStream;
|
|
227
|
+
}
|
|
133
228
|
try {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
229
|
+
// `batchId` names the file for a human reading the directory;
|
|
230
|
+
// `captureSeq` separates batches within this process and `captureNonce`
|
|
231
|
+
// separates it from every other process - see both fields.
|
|
232
|
+
const key = `${this.batchId.replace(/[^a-zA-Z0-9]+/g, '-')}-${process.pid}-${this.captureSeq}-${this.captureNonce}`;
|
|
233
|
+
const path = (0, cache_1.batchOutputPathForKey)(key);
|
|
234
|
+
(0, fs_1.mkdirSync)((0, path_1.dirname)(path), { recursive: true });
|
|
235
|
+
const stream = (0, fs_1.createWriteStream)(path);
|
|
236
|
+
// Mandatory, not defensive: a write error reaches a stream as an 'error'
|
|
237
|
+
// event, and an unhandled one is an uncaught exception that would take
|
|
238
|
+
// down a run with nothing else wrong with it. Stop capturing, keep what
|
|
239
|
+
// already reached the file — the head of the batch's log, where a
|
|
240
|
+
// compiler's first non-cascading errors are — and put everything after
|
|
241
|
+
// it on the terminal.
|
|
242
|
+
stream.on('error', (e) => {
|
|
243
|
+
this.capturedOutputFailed = true;
|
|
244
|
+
this.resumeCapturedSources();
|
|
245
|
+
this.warnCaptureFailed(e.message);
|
|
246
|
+
});
|
|
247
|
+
this.capturedOutputPath = path;
|
|
248
|
+
this.capturedOutputStream = stream;
|
|
150
249
|
}
|
|
151
250
|
catch (e) {
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
// full disk or a read-only data directory would take down a run that
|
|
155
|
-
// otherwise had nothing wrong with it. The capture is an optimization
|
|
156
|
-
// that the common path discards anyway, so give it up and put the bytes
|
|
157
|
-
// back on the terminal instead of losing both them and the run.
|
|
158
|
-
// Latch on a flag of its own rather than reusing the discard flag: that
|
|
159
|
-
// one makes `capture` return early, which would drop every later chunk
|
|
160
|
-
// on the floor - captured nowhere and printed nowhere.
|
|
251
|
+
// mkdir is the only synchronous throw here; the stream reports its own
|
|
252
|
+
// failures through the handler above.
|
|
161
253
|
this.capturedOutputFailed = true;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
254
|
+
this.warnCaptureFailed(e.message);
|
|
255
|
+
}
|
|
256
|
+
return this.capturedOutputStream;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Flushes and closes the capture so the file is complete before a caller
|
|
260
|
+
* reads it.
|
|
261
|
+
*/
|
|
262
|
+
async flushCapturedOutput() {
|
|
263
|
+
// Before the early return, and unconditionally: `end()` means a pending
|
|
264
|
+
// 'drain' will never arrive, so a source paused for backpressure has
|
|
265
|
+
// nothing left to resume it. Measured: 20/20 runs reach 'finish' with the
|
|
266
|
+
// source still paused.
|
|
267
|
+
const resumed = this.resumeCapturedSources();
|
|
268
|
+
// `resume()` delivers on the next tick while `end()` takes effect in this
|
|
269
|
+
// one, so ending here would strand everything the source still holds - the
|
|
270
|
+
// tail of the log, which is where a build tool puts what went wrong.
|
|
271
|
+
// Bounded, because a source that never empties must not hold the run open.
|
|
272
|
+
for (let turn = 0; turn < BatchProcess.MAX_DRAIN_TURNS &&
|
|
273
|
+
resumed.some((source) => source.readableLength > 0); turn++) {
|
|
274
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
275
|
+
}
|
|
276
|
+
this.capturedOutputClosing = true;
|
|
277
|
+
// The loop's own writes can re-pause a source.
|
|
278
|
+
this.resumeCapturedSources();
|
|
279
|
+
const stream = this.capturedOutputStream;
|
|
280
|
+
if (!stream || stream.destroyed || stream.writableEnded) {
|
|
281
|
+
return;
|
|
183
282
|
}
|
|
283
|
+
await new Promise((resolve) => stream.end(resolve));
|
|
184
284
|
}
|
|
185
285
|
/**
|
|
186
286
|
* Path to the file holding everything held back from the live stream under
|
|
187
287
|
* log grouping, or undefined if nothing was captured. Used to render the whole
|
|
188
288
|
* batch as one fold, so output no task claimed is not lost.
|
|
189
289
|
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* same file instead of minting a second numbered one that nothing cleans up.
|
|
194
|
-
* The caller reads the file once, synchronously, while rendering the fold, so
|
|
195
|
-
* anything arriving after that read is not shown; writes are unbuffered, so
|
|
196
|
-
* the read always sees a complete prefix of what has arrived by then.
|
|
290
|
+
* Not valid to read before `flushCapturedOutput`; that flush ends the stream,
|
|
291
|
+
* so a chunk arriving afterwards - a worker's stdout can deliver past the
|
|
292
|
+
* exit event `getResults()` settles on - is dropped rather than appended.
|
|
197
293
|
*/
|
|
198
294
|
getCapturedOutputPath() {
|
|
199
295
|
return this.capturedOutputPath;
|
|
@@ -204,9 +300,9 @@ class BatchProcess {
|
|
|
204
300
|
this.releaseCapturedOutput();
|
|
205
301
|
}
|
|
206
302
|
/**
|
|
207
|
-
*
|
|
208
|
-
* read. Tolerates a partially-initialized capture, since it also
|
|
209
|
-
* opening or writing the file is what failed.
|
|
303
|
+
* Destroys the stream and unlinks the file, leaving no path behind for a
|
|
304
|
+
* caller to read. Tolerates a partially-initialized capture, since it also
|
|
305
|
+
* runs when opening or writing the file is what failed.
|
|
210
306
|
*/
|
|
211
307
|
releaseCapturedOutput() {
|
|
212
308
|
this.closeCapturedOutput();
|
|
@@ -223,14 +319,12 @@ class BatchProcess {
|
|
|
223
319
|
this.capturedOutputPath = undefined;
|
|
224
320
|
}
|
|
225
321
|
}
|
|
226
|
-
/**
|
|
322
|
+
/** Destroys the stream, dropping anything still buffered. The file stays. */
|
|
227
323
|
closeCapturedOutput() {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
catch { }
|
|
233
|
-
this.capturedOutputFd = undefined;
|
|
324
|
+
this.resumeCapturedSources();
|
|
325
|
+
if (this.capturedOutputStream) {
|
|
326
|
+
this.capturedOutputStream.destroy();
|
|
327
|
+
this.capturedOutputStream = undefined;
|
|
234
328
|
}
|
|
235
329
|
}
|
|
236
330
|
// Resolves on the CompleteBatchExecution message, not process exit: the
|
|
@@ -263,4 +357,6 @@ class BatchProcess {
|
|
|
263
357
|
}
|
|
264
358
|
}
|
|
265
359
|
exports.BatchProcess = BatchProcess;
|
|
266
|
-
BatchProcess.
|
|
360
|
+
BatchProcess.captureSeq = 0;
|
|
361
|
+
/** Turns `flushCapturedOutput` waits for a resumed source to empty. */
|
|
362
|
+
BatchProcess.MAX_DRAIN_TURNS = 100;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { OutputStyle } from '../command-line/yargs-utils/shared-options';
|
|
1
2
|
import { NxJsonConfiguration } from '../config/nx-json';
|
|
2
3
|
import { ProjectGraph } from '../config/project-graph';
|
|
3
4
|
import { Task, TaskGraph } from '../config/task-graph';
|
|
@@ -20,7 +21,10 @@ export declare class TaskOrchestrator {
|
|
|
20
21
|
private readonly options;
|
|
21
22
|
private readonly bail;
|
|
22
23
|
private readonly daemon;
|
|
23
|
-
|
|
24
|
+
/** What the user named; undefined means they named nothing. */
|
|
25
|
+
private readonly specifiedOutputStyle;
|
|
26
|
+
/** What this run renders with, after defaults. */
|
|
27
|
+
private readonly resolvedOutputStyle;
|
|
24
28
|
private readonly fullTaskGraph;
|
|
25
29
|
private taskDetails;
|
|
26
30
|
private cache;
|
|
@@ -57,7 +61,14 @@ export declare class TaskOrchestrator {
|
|
|
57
61
|
private continuousTaskExitHandled;
|
|
58
62
|
private cleanupPromise;
|
|
59
63
|
private signalHandlers;
|
|
60
|
-
|
|
64
|
+
private tasksWithPersistedOutput;
|
|
65
|
+
/** Batches whose worker log was handed to the life cycle, so it must survive. */
|
|
66
|
+
private announcedBatchLogs;
|
|
67
|
+
constructor(hasher: TaskHasher, initiatingProject: string | undefined, initiatingTasks: Task[], projectGraph: ProjectGraph, taskGraph: TaskGraph, nxJson: NxJsonConfiguration, options: NxArgs & DefaultTasksRunnerOptions, bail: boolean, daemon: DaemonClient,
|
|
68
|
+
/** What the user named; undefined means they named nothing. */
|
|
69
|
+
specifiedOutputStyle: OutputStyle | undefined,
|
|
70
|
+
/** What this run renders with, after defaults. */
|
|
71
|
+
resolvedOutputStyle: OutputStyle, fullTaskGraph?: TaskGraph);
|
|
61
72
|
init(): Promise<void>;
|
|
62
73
|
run(): Promise<{
|
|
63
74
|
[k: string]: TaskStatus;
|
|
@@ -125,6 +136,15 @@ export declare class TaskOrchestrator {
|
|
|
125
136
|
private hashBatchTasks;
|
|
126
137
|
applyFromCacheOrRunBatch(doNotSkipCache: boolean, batch: Batch, groupId: number): Promise<TaskResult[]>;
|
|
127
138
|
private runBatch;
|
|
139
|
+
/**
|
|
140
|
+
* Tells the life cycle where the batch worker's own log is, when something
|
|
141
|
+
* failed and a style that prints nothing would otherwise leave it unread.
|
|
142
|
+
*
|
|
143
|
+
* The path is announced rather than the bytes copied into a task: one worker
|
|
144
|
+
* produces one log, it explains the batch rather than any single task, and a
|
|
145
|
+
* task's own output file is read back verbatim on a cache hit.
|
|
146
|
+
*/
|
|
147
|
+
private announceBatchWorkerLog;
|
|
128
148
|
/**
|
|
129
149
|
* Rendering a batch's output must never change the batch's results. A throw
|
|
130
150
|
* from the printer would otherwise land in `runBatch`'s own error handling:
|
|
@@ -229,6 +249,48 @@ export declare class TaskOrchestrator {
|
|
|
229
249
|
startContinuousTask(task: Task, groupId: number): Promise<RunningTask | SharedRunningTask>;
|
|
230
250
|
private preRunSteps;
|
|
231
251
|
private postRunSteps;
|
|
252
|
+
/**
|
|
253
|
+
* The results `cache.put` will write, in the shape it wants them. Pulled out
|
|
254
|
+
* of postRunSteps so the terminal-output backstop can be told exactly which
|
|
255
|
+
* tasks the cache is already writing a file for.
|
|
256
|
+
*/
|
|
257
|
+
private resultsToCache;
|
|
258
|
+
/**
|
|
259
|
+
* Guarantee that every task that actually ran leaves its terminal output at
|
|
260
|
+
* `<cacheDir>/terminalOutputs/<hash>`, whatever its cache setting, output
|
|
261
|
+
* style, or batch membership. That path is what `--output-style=summary`
|
|
262
|
+
* addresses each failure by, what the DB cache reads back on a hit
|
|
263
|
+
* (`build_cached_result`), and what Nx Cloud falls back to reading when a
|
|
264
|
+
* task's in-memory output is undefined, so a task that reaches a terminal
|
|
265
|
+
* state without a file there is a dangling reference.
|
|
266
|
+
*
|
|
267
|
+
* Batch tasks are why this exists. Their output only ever arrives over IPC,
|
|
268
|
+
* so the sole thing that ever put it on disk was `cache.put` — leaving a
|
|
269
|
+
* `cache:false` batch task (the shape CI runs under `NX_BATCH_MODE`) with no
|
|
270
|
+
* file at all.
|
|
271
|
+
*
|
|
272
|
+
* Written exactly once per task: tasks whose runner owns the file are
|
|
273
|
+
* recorded in `tasksWithPersistedOutput`, and tasks `cache.put` is about to
|
|
274
|
+
* write are skipped here. Cache hits are skipped by status — their output was
|
|
275
|
+
* read from this very file — except a replayed cached *failure*, which comes
|
|
276
|
+
* back as `failure` and is rewritten with the bytes it was just read with.
|
|
277
|
+
* Skipped tasks never ran, so there is nothing to write.
|
|
278
|
+
*
|
|
279
|
+
* Every file written without a cache entry behind it is then registered with
|
|
280
|
+
* the cache, because `removeOldCacheRecords` only collects hashes it finds in
|
|
281
|
+
* the database — an unregistered file would never be cleaned up. That covers
|
|
282
|
+
* files this method wrote AND ones a runner wrote, which are equally
|
|
283
|
+
* invisible to the GC.
|
|
284
|
+
*/
|
|
285
|
+
private persistTerminalOutputs;
|
|
286
|
+
/**
|
|
287
|
+
* Register a continuous task's terminal output with the cache so the GC can
|
|
288
|
+
* collect it. Continuous tasks never reach postRunSteps — their file is
|
|
289
|
+
* written by whichever runner ran them, as the process exits — so this is
|
|
290
|
+
* the only place their hash gets recorded. Read off disk rather than from a
|
|
291
|
+
* result, because a continuous task completes without one.
|
|
292
|
+
*/
|
|
293
|
+
private recordContinuousTerminalOutput;
|
|
232
294
|
private scheduleNextTasksAndReleaseThreads;
|
|
233
295
|
private complete;
|
|
234
296
|
/**
|