@empire-builder-kit/nx 1.0.0-rc.44 → 1.0.0-rc.46
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 +3 -3
- package/src/blueprints/external-sandbox.d.ts +1 -1
- package/src/cli/main.d.ts +11 -5
- package/src/cli/main.js +88 -29
- package/src/container-images.d.ts +1 -1
- package/src/container-images.js +1 -1
- package/src/developer-agent/generator-planning.js +10 -3
- package/src/developer-agent/operation-registry.js +1 -1
- package/src/executors/deployment-plan/deployment-plan.js +5 -1
- package/src/executors/deployment-plan/schema.json +1 -1
- package/src/executors/fleet/fleet.js +4 -0
- package/src/executors/fleet/schema.json +1 -1
- package/src/executors/github-bootstrap/github-bootstrap.d.ts +3 -0
- package/src/executors/github-bootstrap/github-bootstrap.js +28 -0
- package/src/executors/github-bootstrap/schema.json +14 -0
- package/src/executors/local-deploy/federated-credential-transport.d.ts +4 -3
- package/src/executors/local-deploy/federated-credential-transport.js +15 -5
- package/src/foundation/cost-estimate.d.ts +8 -3
- package/src/foundation/cost-estimate.js +42 -19
- package/src/foundation/index.d.ts +1 -0
- package/src/foundation/index.js +1 -0
- package/src/foundation/local-private-smoke-access.js +6 -0
- package/src/foundation/logging.d.ts +3 -1
- package/src/foundation/logging.js +8 -1
- package/src/foundation/observability.d.ts +42 -0
- package/src/foundation/observability.js +181 -0
- package/src/foundation/preflight.js +1 -1
- package/src/generators/function/function.js +5 -2
- package/src/generators/observability-infrastructure.d.ts +2 -0
- package/src/generators/observability-infrastructure.js +31 -0
- package/src/generators/observability-policy.d.ts +4 -0
- package/src/generators/observability-policy.js +23 -0
- package/src/generators/preset/dependency-overrides.d.ts +17 -6
- package/src/generators/preset/dependency-overrides.js +17 -6
- package/src/generators/preset/tool-versions.d.ts +2 -2
- package/src/generators/preset/tool-versions.js +2 -2
- package/src/generators/preset/workspace-files-adopter-skills.js +28 -17
- package/src/generators/preset/workspace-files-agent-development.d.ts +9 -0
- package/src/generators/preset/workspace-files-agent-development.js +42 -0
- package/src/generators/preset/workspace-files-thin-deploy.js +17 -4
- package/src/generators/preset/workspace-files-thin-docs.js +10 -22
- package/src/generators/preset/workspace-files.d.ts +1 -0
- package/src/generators/preset/workspace-files.js +120 -35
- package/src/generators/slice/built-in-plan-alarm-identity.d.ts +173 -0
- package/src/generators/slice/built-in-plan-alarm-identity.js +202 -0
- package/src/generators/slice/built-in-plan-api-contract-files.js +136 -0
- package/src/generators/slice/built-in-plan-data-files.js +10 -3
- package/src/generators/slice/built-in-plan-database-lifecycle-files.js +1 -1
- package/src/generators/slice/built-in-plan-event-contract-literal.d.ts +6 -0
- package/src/generators/slice/built-in-plan-event-contract-literal.js +52 -0
- package/src/generators/slice/built-in-plan-infrastructure-files.js +304 -144
- package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.js +2 -2
- package/src/generators/slice/built-in-plan-metadata-files.js +37 -2
- package/src/generators/slice/built-in-plan-operations-files.js +106 -6
- package/src/generators/slice/built-in-plan-project-files.js +1 -0
- package/src/generators/slice/built-in-plan-release-files.js +2 -44
- package/src/generators/slice/built-in-plan-reliability-files.js +222 -236
- package/src/generators/slice/built-in-plan-shared.d.ts +29 -3
- package/src/generators/slice/built-in-plan-shared.js +29 -2
- package/src/generators/slice/built-in-plan-verification-files.js +0 -1
- package/src/generators/slice/built-in-plan-web-files.js +22 -6
- package/src/generators/slice/built-in-plan.js +2 -2
- package/src/generators/slice/slice.js +2 -0
- package/src/generators/upgrade/upgrade.d.ts +4 -3
- package/src/generators/upgrade/upgrade.js +139 -29
- package/src/generators/workload/frozen-container.d.ts +1 -1
- package/src/generators/workload/reliability-registration.d.ts +1 -1
- package/src/generators/workload/reliability-registration.js +9 -9
- package/src/generators/workload/workload.d.ts +1 -1
- package/src/generators/workload/workload.js +32 -10
- package/src/git-policy/github-bootstrap.d.ts +18 -0
- package/src/git-policy/github-bootstrap.js +99 -6
- package/src/local-dev/dev-command-core.d.ts +24 -3
- package/src/local-dev/dev-command-core.js +124 -12
- package/src/local-dev/errors.d.ts +19 -1
- package/src/local-dev/errors.js +18 -1
- package/src/local-dev/fleet-client.d.ts +64 -6
- package/src/local-dev/fleet-client.js +189 -15
- package/src/local-dev/fleet-process.d.ts +47 -2
- package/src/local-dev/fleet-process.js +248 -31
- package/src/local-dev/fleet-runtime.d.ts +37 -0
- package/src/local-dev/fleet-runtime.js +127 -69
- package/src/local-dev/fleet-session.d.ts +1 -0
- package/src/local-dev/fleet-session.js +83 -7
- package/src/local-dev/fleet-state.d.ts +5 -0
- package/src/local-dev/fleet-state.js +11 -2
- package/src/local-dev/fleet-supervisor-daemon.js +1 -5
- package/src/local-dev/fleet-supervisor.d.ts +7 -0
- package/src/local-dev/fleet-supervisor.js +83 -12
- package/src/local-dev/slice-runner.d.ts +19 -1
- package/src/local-dev/slice-runner.js +290 -91
- package/src/repository-policy/deployment-plan.d.ts +1 -1
- package/src/repository-policy/deployment-plan.js +16 -1
- package/src/secrets/generated-aws-control-plane.d.ts +11 -1
- package/src/secrets/generated-aws-control-plane.js +92 -29
- package/src/secrets/operator.d.ts +3 -2
- package/src/secrets/operator.js +27 -5
- package/src/supply-chain/blueprint-verification-authority.js +24 -3
- package/src/supply-chain/generated-files.js +9 -0
- package/src/supply-chain/sbom.js +74 -12
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FleetClient = void 0;
|
|
3
|
+
exports.FleetClient = exports.FLEET_OPERATION_OBSERVATION = exports.FLEET_SUPERVISOR_HEARTBEAT_STALE_MS = void 0;
|
|
4
|
+
exports.fleetOperationFailure = fleetOperationFailure;
|
|
4
5
|
const node_crypto_1 = require("node:crypto");
|
|
5
6
|
const control_contract_js_1 = require("./control-contract.js");
|
|
6
7
|
const contract_validation_js_1 = require("./contract-validation.js");
|
|
@@ -8,6 +9,56 @@ const errors_js_1 = require("./errors.js");
|
|
|
8
9
|
const fleet_ipc_js_1 = require("./fleet-ipc.js");
|
|
9
10
|
const fleet_state_js_1 = require("./fleet-state.js");
|
|
10
11
|
const private_state_js_1 = require("./private-state.js");
|
|
12
|
+
/** A supervisor whose authenticated status keeps answering with the same
|
|
13
|
+
* heartbeat for this long is not making progress. The supervisor writes its
|
|
14
|
+
* heartbeat every 5 s; Windows identity captures can block its loop longer.
|
|
15
|
+
* The window must also span enough consecutive status reads (see
|
|
16
|
+
* `waitForOperationOutcome`), so a host sleep that jumps the clock cannot
|
|
17
|
+
* trip it before the supervisor's next heartbeat. */
|
|
18
|
+
exports.FLEET_SUPERVISOR_HEARTBEAT_STALE_MS = Object.freeze({
|
|
19
|
+
default: 30_000,
|
|
20
|
+
win32: 60_000,
|
|
21
|
+
});
|
|
22
|
+
/** Defaults for watching a supervised operation. None of them is an operation
|
|
23
|
+
* deadline: without an explicit cap the client waits for the real outcome. */
|
|
24
|
+
exports.FLEET_OPERATION_OBSERVATION = Object.freeze({
|
|
25
|
+
pollMs: 200,
|
|
26
|
+
/** Progress is reported on every Slice change and at least this often. */
|
|
27
|
+
progressIntervalMs: 30_000,
|
|
28
|
+
/** Status (heartbeat and Slice progress) is read at most this often. */
|
|
29
|
+
statusIntervalMs: 2_000,
|
|
30
|
+
/** Consecutive unreachable polls tolerated before the wait fails. */
|
|
31
|
+
unreachableLimit: 6,
|
|
32
|
+
});
|
|
33
|
+
function defaultSleep(milliseconds, signal) {
|
|
34
|
+
return new Promise((resolvePromise) => {
|
|
35
|
+
if (signal?.aborted) {
|
|
36
|
+
resolvePromise();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const settle = () => {
|
|
40
|
+
clearTimeout(timer);
|
|
41
|
+
signal?.removeEventListener('abort', settle);
|
|
42
|
+
resolvePromise();
|
|
43
|
+
};
|
|
44
|
+
const timer = setTimeout(settle, milliseconds);
|
|
45
|
+
signal?.addEventListener('abort', settle, { once: true });
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function formatObservedDuration(milliseconds) {
|
|
49
|
+
if (milliseconds < 1_000)
|
|
50
|
+
return `${milliseconds}ms`;
|
|
51
|
+
const seconds = Math.round(milliseconds / 1_000);
|
|
52
|
+
const minutes = Math.floor(seconds / 60);
|
|
53
|
+
return minutes === 0
|
|
54
|
+
? `${seconds}s`
|
|
55
|
+
: `${minutes}m${String(seconds % 60).padStart(2, '0')}s`;
|
|
56
|
+
}
|
|
57
|
+
/** Terminal failure as an error that keeps the supervisor's persisted cause. */
|
|
58
|
+
function fleetOperationFailure(operation) {
|
|
59
|
+
const classification = operation.failureClassification ?? 'internal-error';
|
|
60
|
+
return new errors_js_1.LocalDevContractError(classification, `Fleet ${operation.command} operation ${operation.id} failed (${classification})${operation.failureMessage ? `: ${operation.failureMessage}` : '.'}`);
|
|
61
|
+
}
|
|
11
62
|
function clientFailure(response) {
|
|
12
63
|
if (!('error' in response)) {
|
|
13
64
|
throw new errors_js_1.LocalDevContractError('invalid-state', 'Expected a Fleet control failure response.');
|
|
@@ -67,16 +118,33 @@ function validateOperation(value) {
|
|
|
67
118
|
}
|
|
68
119
|
class FleetClient {
|
|
69
120
|
#capability;
|
|
121
|
+
#now;
|
|
122
|
+
#observation;
|
|
70
123
|
#paths;
|
|
71
124
|
#requestId;
|
|
72
125
|
#send;
|
|
73
|
-
|
|
126
|
+
#sleep;
|
|
127
|
+
constructor(paths, security = {}, effects = {}, observation = {}) {
|
|
74
128
|
this.#paths = paths;
|
|
75
129
|
this.#capability = (0, private_state_js_1.readPrivateFile)(paths.capability, security)
|
|
76
130
|
.toString('utf8')
|
|
77
131
|
.trim();
|
|
132
|
+
this.#now = effects.now ?? (() => Date.now());
|
|
78
133
|
this.#requestId = effects.requestId ?? (() => (0, node_crypto_1.randomUUID)());
|
|
79
134
|
this.#send = effects.send ?? fleet_ipc_js_1.sendFleetControlRequest;
|
|
135
|
+
this.#sleep = effects.sleep ?? defaultSleep;
|
|
136
|
+
this.#observation = {
|
|
137
|
+
progressIntervalMs: observation.progressIntervalMs ??
|
|
138
|
+
exports.FLEET_OPERATION_OBSERVATION.progressIntervalMs,
|
|
139
|
+
staleHeartbeatMs: observation.staleHeartbeatMs ??
|
|
140
|
+
(process.platform === 'win32'
|
|
141
|
+
? exports.FLEET_SUPERVISOR_HEARTBEAT_STALE_MS.win32
|
|
142
|
+
: exports.FLEET_SUPERVISOR_HEARTBEAT_STALE_MS.default),
|
|
143
|
+
statusIntervalMs: observation.statusIntervalMs ??
|
|
144
|
+
exports.FLEET_OPERATION_OBSERVATION.statusIntervalMs,
|
|
145
|
+
unreachableLimit: observation.unreachableLimit ??
|
|
146
|
+
exports.FLEET_OPERATION_OBSERVATION.unreachableLimit,
|
|
147
|
+
};
|
|
80
148
|
}
|
|
81
149
|
async #request(request) {
|
|
82
150
|
const response = await this.#send(this.#paths.controlSocket, {
|
|
@@ -128,22 +196,128 @@ class FleetClient {
|
|
|
128
196
|
payload: { operationId },
|
|
129
197
|
}));
|
|
130
198
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
199
|
+
/** Wait for a terminal operation record, `succeeded` or `failed`.
|
|
200
|
+
*
|
|
201
|
+
* There is no default deadline: an operation that is still progressing is
|
|
202
|
+
* observed until it settles. The wait ends early only on an explicit
|
|
203
|
+
* `timeoutMs` cap (`observation-timeout`), on `signal` abort
|
|
204
|
+
* (`observation-interrupted`), or when the supervisor itself stops making
|
|
205
|
+
* progress (`supervisor-unreachable`: repeated unreachable polls or a
|
|
206
|
+
* heartbeat that no longer advances). Ending observation never cancels the
|
|
207
|
+
* supervised operation.
|
|
208
|
+
*/
|
|
209
|
+
async waitForOperationOutcome(operationId, options = {}) {
|
|
210
|
+
const pollMs = options.pollMs ?? exports.FLEET_OPERATION_OBSERVATION.pollMs;
|
|
211
|
+
const tuning = this.#observation;
|
|
212
|
+
const startedAt = this.#now();
|
|
213
|
+
const deadline = options.timeoutMs === undefined
|
|
214
|
+
? undefined
|
|
215
|
+
: startedAt + options.timeoutMs;
|
|
216
|
+
let latest;
|
|
217
|
+
let unreachable = 0;
|
|
218
|
+
let nextStatusAt = startedAt + tuning.statusIntervalMs;
|
|
219
|
+
// A heartbeat is stale only when it stays unchanged both for the stale
|
|
220
|
+
// window by the clock and across enough consecutive status reads to cover
|
|
221
|
+
// that window at the status interval. After a host sleep the clock jumps
|
|
222
|
+
// at once, but the reads still have to accumulate, which gives the
|
|
223
|
+
// supervisor time for its next heartbeat.
|
|
224
|
+
const staleReadLimit = Math.max(1, Math.ceil(tuning.staleHeartbeatMs / Math.max(1, tuning.statusIntervalMs)));
|
|
225
|
+
let heartbeat;
|
|
226
|
+
let reportedSummary;
|
|
227
|
+
let reportedAt = startedAt;
|
|
228
|
+
const label = () => `Fleet ${latest ? `${latest.command} ` : ''}operation ${operationId}`;
|
|
229
|
+
const ended = (classification, message, elapsedMs = this.#now() - startedAt) => new errors_js_1.FleetObservationError(classification, message, {
|
|
230
|
+
elapsedMs,
|
|
231
|
+
...(latest
|
|
232
|
+
? {
|
|
233
|
+
lastObservedState: latest.state,
|
|
234
|
+
}
|
|
235
|
+
: {}),
|
|
236
|
+
operationId,
|
|
237
|
+
...(classification === 'observation-timeout'
|
|
238
|
+
? { timeoutMs: options.timeoutMs }
|
|
239
|
+
: {}),
|
|
240
|
+
});
|
|
241
|
+
while (true) {
|
|
242
|
+
if (options.signal?.aborted) {
|
|
243
|
+
const elapsedMs = this.#now() - startedAt;
|
|
244
|
+
throw ended('observation-interrupted', `Stopped watching ${label()} after ${formatObservedDuration(elapsedMs)} on interruption; the supervised operation continues. Check ebk dev status and ebk dev logs before retrying.`, elapsedMs);
|
|
245
|
+
}
|
|
246
|
+
if (deadline !== undefined && this.#now() >= deadline) {
|
|
247
|
+
throw ended('observation-timeout', `Stopped watching ${label()} after the explicit ${formatObservedDuration(options.timeoutMs)} --timeout cap; it was last ${latest?.state ?? 'unobserved'} and continues in the supervisor. Check ebk dev status and ebk dev logs before retrying.`);
|
|
248
|
+
}
|
|
249
|
+
let operation;
|
|
250
|
+
try {
|
|
251
|
+
operation = await this.operationStatus(operationId);
|
|
252
|
+
unreachable = 0;
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
if (!(error instanceof errors_js_1.LocalDevContractError) ||
|
|
256
|
+
error.classification !== 'supervisor-unreachable')
|
|
257
|
+
throw error;
|
|
258
|
+
unreachable += 1;
|
|
259
|
+
if (unreachable >= tuning.unreachableLimit) {
|
|
260
|
+
throw ended('supervisor-unreachable', `${label()} could not be observed: the supervisor did not answer ${unreachable} consecutive polls (${error.message}). Check ebk dev status and ebk dev ps before retrying.`);
|
|
261
|
+
}
|
|
262
|
+
await this.#pause(Math.min(1_000 * 2 ** (unreachable - 1), 5_000), deadline, options.signal);
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if (operation.state === 'succeeded' || operation.state === 'failed')
|
|
138
266
|
return operation;
|
|
139
|
-
|
|
140
|
-
|
|
267
|
+
latest = operation;
|
|
268
|
+
const now = this.#now();
|
|
269
|
+
if (now >= nextStatusAt) {
|
|
270
|
+
nextStatusAt = now + tuning.statusIntervalMs;
|
|
271
|
+
// Status is advisory: a refused or malformed read (for example while
|
|
272
|
+
// the supervisor is shutting down) never ends the wait by itself.
|
|
273
|
+
const state = await this.status().catch(() => undefined);
|
|
274
|
+
if (state) {
|
|
275
|
+
const observedAt = this.#now();
|
|
276
|
+
if (heartbeat?.value !== state.heartbeatAt) {
|
|
277
|
+
heartbeat = { observedAt, staleReads: 0, value: state.heartbeatAt };
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
heartbeat.staleReads += 1;
|
|
281
|
+
if (heartbeat.staleReads >= staleReadLimit &&
|
|
282
|
+
observedAt - heartbeat.observedAt > tuning.staleHeartbeatMs) {
|
|
283
|
+
throw ended('supervisor-unreachable', `${label()} could not be observed: the supervisor heartbeat has not advanced since ${state.heartbeatAt} (${formatObservedDuration(observedAt - heartbeat.observedAt)}, ${heartbeat.staleReads} consecutive status reads). Check ebk dev status and ebk dev ps before retrying.`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (options.onProgress) {
|
|
287
|
+
const slices = state.slices.filter(({ name }) => operation.slices.includes(name));
|
|
288
|
+
const summary = JSON.stringify(slices.map(({ cleanup, name, restartAttempts, routeState }) => [
|
|
289
|
+
name,
|
|
290
|
+
routeState,
|
|
291
|
+
cleanup,
|
|
292
|
+
restartAttempts,
|
|
293
|
+
]));
|
|
294
|
+
if (summary !== reportedSummary ||
|
|
295
|
+
observedAt - reportedAt >= tuning.progressIntervalMs) {
|
|
296
|
+
reportedSummary = summary;
|
|
297
|
+
reportedAt = observedAt;
|
|
298
|
+
options.onProgress({
|
|
299
|
+
elapsedMs: observedAt - startedAt,
|
|
300
|
+
operation,
|
|
301
|
+
slices,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
141
306
|
}
|
|
142
|
-
await
|
|
143
|
-
setTimeout(resolvePromise, pollMs);
|
|
144
|
-
});
|
|
307
|
+
await this.#pause(pollMs, deadline, options.signal);
|
|
145
308
|
}
|
|
146
|
-
|
|
309
|
+
}
|
|
310
|
+
/** Throwing form: resolves only on `succeeded`; a terminal `failed` record
|
|
311
|
+
* becomes an error carrying its persisted classification and cause. */
|
|
312
|
+
async waitForOperation(operationId, options = {}) {
|
|
313
|
+
const operation = await this.waitForOperationOutcome(operationId, options);
|
|
314
|
+
if (operation.state === 'failed')
|
|
315
|
+
throw fleetOperationFailure(operation);
|
|
316
|
+
return operation;
|
|
317
|
+
}
|
|
318
|
+
async #pause(milliseconds, deadline, signal) {
|
|
319
|
+
const remaining = deadline === undefined ? milliseconds : deadline - this.#now();
|
|
320
|
+
await this.#sleep(Math.max(0, Math.min(milliseconds, remaining)), signal);
|
|
147
321
|
}
|
|
148
322
|
async shutdown(idempotencyKey = (0, node_crypto_1.randomUUID)()) {
|
|
149
323
|
await this.#request({
|
|
@@ -9,6 +9,11 @@ export interface FleetProcessLaunch {
|
|
|
9
9
|
attempt: number;
|
|
10
10
|
child: ChildProcess;
|
|
11
11
|
}
|
|
12
|
+
/** How an owned process ended: an exit status or a terminating signal. */
|
|
13
|
+
export interface FleetProcessExit {
|
|
14
|
+
code: number | null;
|
|
15
|
+
signal: string | null;
|
|
16
|
+
}
|
|
12
17
|
export interface FleetProcessEffects {
|
|
13
18
|
/** Native provisioning may outlast HTTP readiness. This is an owned launch
|
|
14
19
|
* notification, not an HTTP-health result. Non-native adapters omit it. */
|
|
@@ -17,15 +22,39 @@ export interface FleetProcessEffects {
|
|
|
17
22
|
cleanup?: () => Promise<void>;
|
|
18
23
|
delay?: (milliseconds: number, signal: AbortSignal) => Promise<void>;
|
|
19
24
|
launch: (attempt: number) => FleetProcessLaunch;
|
|
20
|
-
|
|
25
|
+
/** `true` is healthy, `'unhealthy'` is an HTTP response that is not OK,
|
|
26
|
+
* and `false` is no response (refused, reset, or unanswered). */
|
|
27
|
+
probe?: (url: URL, signal: AbortSignal) => Promise<FleetProbeResult>;
|
|
21
28
|
prepareRestart?: (child: ChildProcess) => Promise<void>;
|
|
29
|
+
/** Stop the writer while the owned process keeps its pending cleanup
|
|
30
|
+
* authority. A coordinating runner stays alive and later runs declared
|
|
31
|
+
* cleanup itself when stopped. Without this effect, quiescence writes the
|
|
32
|
+
* restart intent and terminates the child. */
|
|
33
|
+
quiesce?: (child: ChildProcess) => Promise<void>;
|
|
22
34
|
runnerGeneration?: () => string | undefined;
|
|
35
|
+
/** The Slice start target's own exit, when the launched child is a runner
|
|
36
|
+
* that recorded it. The runner exits cleanly after its child crashes, so
|
|
37
|
+
* its own status alone would hide the real failure. */
|
|
38
|
+
startTargetExit?: (child: ChildProcess) => FleetProcessExit | undefined;
|
|
23
39
|
terminate?: (child: ChildProcess) => Promise<void>;
|
|
24
40
|
}
|
|
41
|
+
export type FleetProbeResult = boolean | 'unhealthy';
|
|
42
|
+
/** Web readiness after launch is measured against a target, not enforced as
|
|
43
|
+
* a deadline: past it the controller logs once and keeps waiting while the
|
|
44
|
+
* Slice makes progress. */
|
|
45
|
+
export declare const FLEET_READINESS_TARGET_MS = 120000;
|
|
46
|
+
/** Readiness fails only when nothing has progressed for this long: no output
|
|
47
|
+
* and no state change while the health route gives no answer, or only
|
|
48
|
+
* unhealthy answers. Request logs a probe causes are not progress for an
|
|
49
|
+
* answering but unhealthy application, so that path ignores output. */
|
|
50
|
+
export declare const FLEET_READINESS_STALL_MS = 120000;
|
|
51
|
+
/** Recent output lines carried into a startup failure message. */
|
|
52
|
+
export declare const FLEET_FAILURE_OUTPUT_LINES = 4;
|
|
25
53
|
export interface FleetProcessControllerOptions {
|
|
26
54
|
adapter: LocalDevAdapter;
|
|
27
|
-
healthTimeoutMs?: number;
|
|
28
55
|
provisioningTimeoutMs?: number;
|
|
56
|
+
readinessStallMs?: number;
|
|
57
|
+
readinessTargetMs?: number;
|
|
29
58
|
logStore?: FleetLogStore;
|
|
30
59
|
maxRestartAttempts: number;
|
|
31
60
|
name: string;
|
|
@@ -43,12 +72,22 @@ export declare function planFleetRestart(completedRestartAttempts: number, maxRe
|
|
|
43
72
|
export declare function assertOwnedGroupAbsent(pid: number, deadline?: number): Promise<void>;
|
|
44
73
|
export declare function terminateOwnedChild(child: ChildProcess, ownedIdentity?: FleetProcessIdentity): Promise<void>;
|
|
45
74
|
export declare const FLEET_RUNNER_STOP_MESSAGE = "ebk-fleet-runner-stop";
|
|
75
|
+
export declare const FLEET_RUNNER_QUIESCE_MESSAGE = "ebk-fleet-runner-quiesce";
|
|
76
|
+
export declare const FLEET_RUNNER_QUIESCED_MESSAGE = "ebk-fleet-runner-quiesced";
|
|
46
77
|
/** A runner coordinates detached children and native cleanup. Never force-kill
|
|
47
78
|
* that coordinator on a client observation deadline. An explicit diagnostic
|
|
48
79
|
* deadline retains live ownership and reports failure instead of orphaning a
|
|
49
80
|
* writer (and falsely permitting stale-process recovery).
|
|
50
81
|
*/
|
|
51
82
|
export declare function terminateCoordinatingFleetRunner(child: ChildProcess, runnerGeneration: string, timeoutMs?: number): Promise<void>;
|
|
83
|
+
/** Ask the exact runner generation to stop its writer but keep running with
|
|
84
|
+
* pending cleanup authority. It acknowledges once its owned child group is
|
|
85
|
+
* absent, or at once when quiescence reaches it before its writer started.
|
|
86
|
+
* Like the stop, this has no client deadline: the runner bounds its own
|
|
87
|
+
* child termination. A clean exit also settles the request, because the
|
|
88
|
+
* runner then retained its authority in state for a cleanup retry.
|
|
89
|
+
*/
|
|
90
|
+
export declare function quiesceCoordinatingFleetRunner(child: ChildProcess, runnerGeneration: string): Promise<void>;
|
|
52
91
|
export declare class FleetProcessController {
|
|
53
92
|
#private;
|
|
54
93
|
constructor(options: FleetProcessControllerOptions, effects: FleetProcessEffects);
|
|
@@ -62,6 +101,12 @@ export declare class FleetProcessController {
|
|
|
62
101
|
* responsibility for native termination and exact cleanup before down runs. */
|
|
63
102
|
interruptStartup(): void;
|
|
64
103
|
restart(): Promise<void>;
|
|
104
|
+
/** Stop the owned writer without removing its cloud/dependency
|
|
105
|
+
* prerequisites. A Fleet transaction quiesces every selected Slice before
|
|
106
|
+
* reverse cleanup; a failed dependent cleanup must not leave a dependency
|
|
107
|
+
* writer running. A coordinating runner stays alive with pending cleanup
|
|
108
|
+
* authority, so its later cleanup output still reaches this Slice's log. */
|
|
109
|
+
quiesce(): Promise<void>;
|
|
65
110
|
stop(options: {
|
|
66
111
|
cleanup: boolean;
|
|
67
112
|
}): Promise<void>;
|