@bastani/atomic 0.9.60 → 0.9.61-alpha.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/CHANGELOG.md +30 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +144 -65
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +163 -66
- package/dist/builtin/workflows/src/index.js +144 -65
- package/dist/builtin/workflows/src/local-worker-entry.mjs +163 -66
- package/dist/builtin/workflows/src/shared/workflow-infrastructure-error.d.ts +6 -0
- package/docs/workflows/operations.md +4 -2
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
|
@@ -5135,6 +5135,18 @@ function failedOnInfrastructureFault(result) {
|
|
|
5135
5135
|
return true;
|
|
5136
5136
|
return Array.isArray(result.stages) && result.stages.some((stage) => stage?.status === "failed" && (names(stage.failureCode) || names(stage.error)));
|
|
5137
5137
|
}
|
|
5138
|
+
function infrastructureFaultMessage(result) {
|
|
5139
|
+
const names = (value2) => typeof value2 === "string" && (WORKFLOW_INFRASTRUCTURE_FAULTS.has(value2) || workflowInfrastructureFault(value2) !== undefined);
|
|
5140
|
+
if (names(result.error))
|
|
5141
|
+
return result.error;
|
|
5142
|
+
const stage = Array.isArray(result.stages) ? result.stages.find((candidate) => candidate?.status === "failed" && (names(candidate.failureCode) || names(candidate.error))) : undefined;
|
|
5143
|
+
if (typeof stage?.error === "string")
|
|
5144
|
+
return stage.error;
|
|
5145
|
+
if (typeof stage?.failureCode === "string")
|
|
5146
|
+
return stage.failureCode;
|
|
5147
|
+
const code = result.failure?.code;
|
|
5148
|
+
return typeof code === "string" ? code : typeof result.error === "string" ? result.error : "pool fault";
|
|
5149
|
+
}
|
|
5138
5150
|
var WORKFLOW_INFRASTRUCTURE_ERROR_NAME = "WorkflowInfrastructureError", WORKFLOW_INFRASTRUCTURE_FAULTS, MAX_CAUSE_DEPTH = 8, FAULT_PATTERNS, WorkflowInfrastructureError;
|
|
5139
5151
|
var init_workflow_infrastructure_error = __esm(() => {
|
|
5140
5152
|
WORKFLOW_INFRASTRUCTURE_FAULTS = new Set([
|
|
@@ -16878,6 +16890,25 @@ function admissionProcessStopped(pid) {
|
|
|
16878
16890
|
return error.code === "ESRCH";
|
|
16879
16891
|
}
|
|
16880
16892
|
}
|
|
16893
|
+
function workerProcessExited(pid, final = false) {
|
|
16894
|
+
if (admissionProcessStopped(pid))
|
|
16895
|
+
return true;
|
|
16896
|
+
if (process.platform === "linux") {
|
|
16897
|
+
try {
|
|
16898
|
+
const stat = readFileSync2(`/proc/${pid}/stat`, "utf8");
|
|
16899
|
+
return stat.slice(stat.lastIndexOf(")") + 2).startsWith("Z");
|
|
16900
|
+
} catch {
|
|
16901
|
+
return admissionProcessStopped(pid);
|
|
16902
|
+
}
|
|
16903
|
+
}
|
|
16904
|
+
if (!final)
|
|
16905
|
+
return false;
|
|
16906
|
+
try {
|
|
16907
|
+
return execFileSync("ps", ["-o", "stat=", "-p", String(pid)], { encoding: "utf8", timeout: 5000 }).trim().startsWith("Z");
|
|
16908
|
+
} catch {
|
|
16909
|
+
return admissionProcessStopped(pid);
|
|
16910
|
+
}
|
|
16911
|
+
}
|
|
16881
16912
|
function scanProcessGroup(group) {
|
|
16882
16913
|
const members = new Map;
|
|
16883
16914
|
if (process.platform === "linux") {
|
|
@@ -59371,17 +59402,26 @@ function isSameCheckpointValue(stored, next) {
|
|
|
59371
59402
|
const hash = (value2) => durableHash(value2);
|
|
59372
59403
|
return hash(stored) === hash(next);
|
|
59373
59404
|
}
|
|
59405
|
+
function withTimesOf(later, recorded) {
|
|
59406
|
+
const both = (key) => typeof recorded[key] === "number" && typeof later[key] === "number";
|
|
59407
|
+
return {
|
|
59408
|
+
...later,
|
|
59409
|
+
...both("startedAt") ? { startedAt: recorded.startedAt } : {},
|
|
59410
|
+
...both("endedAt") ? { endedAt: recorded.endedAt } : {},
|
|
59411
|
+
...both("completedAt") ? { completedAt: recorded.completedAt } : {}
|
|
59412
|
+
};
|
|
59413
|
+
}
|
|
59374
59414
|
function isRecordedCheckpointValue(stored, next) {
|
|
59375
59415
|
const recorded = stored;
|
|
59376
59416
|
if (isSameCheckpointValue(recorded, next))
|
|
59377
59417
|
return true;
|
|
59378
|
-
|
|
59379
|
-
if (typeof completedAt !== "number")
|
|
59418
|
+
if (typeof recorded.completedAt !== "number")
|
|
59380
59419
|
return false;
|
|
59381
59420
|
const later = next;
|
|
59382
|
-
if (startedAt === undefined !== (later.startedAt === undefined))
|
|
59421
|
+
if (recorded.startedAt === undefined !== (later.startedAt === undefined))
|
|
59383
59422
|
return false;
|
|
59384
|
-
|
|
59423
|
+
const retimed = withTimesOf(later, recorded);
|
|
59424
|
+
return isSameCheckpointValue(recorded.topology !== undefined && later.topology !== undefined ? { ...retimed, topology: withTimesOf(later.topology, recorded.topology) } : retimed, recorded);
|
|
59385
59425
|
}
|
|
59386
59426
|
var MIRROR_FRESH_MS = 2000;
|
|
59387
59427
|
var init_pool_remote_journal = __esm(() => {
|
|
@@ -60417,15 +60457,7 @@ class SqlPoolQueue {
|
|
|
60417
60457
|
}
|
|
60418
60458
|
}
|
|
60419
60459
|
function isRecordedCheckpoint(stored, payload) {
|
|
60420
|
-
|
|
60421
|
-
return true;
|
|
60422
|
-
const { completedAt, startedAt } = JSON.parse(stored);
|
|
60423
|
-
if (typeof completedAt !== "number")
|
|
60424
|
-
return false;
|
|
60425
|
-
const next = JSON.parse(payload);
|
|
60426
|
-
if (startedAt === undefined !== (next.startedAt === undefined))
|
|
60427
|
-
return false;
|
|
60428
|
-
return serializeJson({ ...next, completedAt, ...startedAt === undefined ? {} : { startedAt } }) === stored;
|
|
60460
|
+
return stored === payload || isRecordedCheckpointValue(JSON.parse(stored), JSON.parse(payload));
|
|
60429
60461
|
}
|
|
60430
60462
|
function openSqlPoolQueue(journal, remote) {
|
|
60431
60463
|
const storage = sqlPoolStorage(journal);
|
|
@@ -65176,7 +65208,7 @@ var init_startup_timeout = () => {};
|
|
|
65176
65208
|
import { fork } from "node:child_process";
|
|
65177
65209
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
65178
65210
|
import { createWriteStream } from "node:fs";
|
|
65179
|
-
import { mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
65211
|
+
import { appendFile, mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
65180
65212
|
import { dirname as dirname13, join as join29, resolve as resolve12 } from "node:path";
|
|
65181
65213
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
65182
65214
|
function isRootLeaseLost(error) {
|
|
@@ -65368,6 +65400,9 @@ class PoolCoordinator {
|
|
|
65368
65400
|
incarnations = new Map;
|
|
65369
65401
|
readyWorkers = new Set;
|
|
65370
65402
|
logs = new Map;
|
|
65403
|
+
keptLogs = new Set;
|
|
65404
|
+
unconfirmedExits = new WeakSet;
|
|
65405
|
+
failed = false;
|
|
65371
65406
|
cleanups = new Set;
|
|
65372
65407
|
controlAcks = new Map;
|
|
65373
65408
|
lastHeard = new Map;
|
|
@@ -65415,7 +65450,6 @@ class PoolCoordinator {
|
|
|
65415
65450
|
nextRecoveryAt = 0;
|
|
65416
65451
|
cleanupFailure;
|
|
65417
65452
|
held = new Set;
|
|
65418
|
-
quarantined = new Set;
|
|
65419
65453
|
unreaped = [];
|
|
65420
65454
|
retained = new Map;
|
|
65421
65455
|
retainedTransitions = Promise.resolve();
|
|
@@ -65608,18 +65642,15 @@ class PoolCoordinator {
|
|
|
65608
65642
|
try {
|
|
65609
65643
|
const { survivors, unprobeable } = await reapProcessGroups(this.journal, this.root, { attempt: work });
|
|
65610
65644
|
if (survivors.length > 0) {
|
|
65611
|
-
this.quarantined.add(work.id);
|
|
65612
65645
|
this.unreaped.push({ attempt: work });
|
|
65613
|
-
this.
|
|
65614
|
-
return;
|
|
65646
|
+
this.reportHealth(undefined, `${unconfirmedCleanup(survivors).message}; child ${work.childRunId} of an earlier incarnation replays`);
|
|
65615
65647
|
}
|
|
65616
65648
|
if (unprobeable.length === 0)
|
|
65617
65649
|
await this.releaseRetained(work);
|
|
65618
65650
|
} catch (error) {
|
|
65619
65651
|
this.cleanupFailure ??= error instanceof Error ? error : new Error(String(error));
|
|
65620
65652
|
} finally {
|
|
65621
|
-
|
|
65622
|
-
this.held.delete(work.id);
|
|
65653
|
+
this.held.delete(work.id);
|
|
65623
65654
|
}
|
|
65624
65655
|
}
|
|
65625
65656
|
releaseRetained(work) {
|
|
@@ -65750,6 +65781,7 @@ class PoolCoordinator {
|
|
|
65750
65781
|
});
|
|
65751
65782
|
}
|
|
65752
65783
|
fail(error) {
|
|
65784
|
+
this.failed = true;
|
|
65753
65785
|
this.port.send({ kind: "failure", error: error.message });
|
|
65754
65786
|
}
|
|
65755
65787
|
failWork(work, error) {
|
|
@@ -66158,7 +66190,11 @@ class PoolCoordinator {
|
|
|
66158
66190
|
terminate();
|
|
66159
66191
|
});
|
|
66160
66192
|
const closed = new Promise((resolve) => child.once("close", () => resolve()));
|
|
66161
|
-
|
|
66193
|
+
let retired = false;
|
|
66194
|
+
const retire = () => {
|
|
66195
|
+
if (retired)
|
|
66196
|
+
return;
|
|
66197
|
+
retired = true;
|
|
66162
66198
|
Promise.race([closed, delay2(STDERR_DRAIN_GRACE_MS)]).then(() => reject(diagnosed(timedOut ? startupTimeoutMessage(startupTimeoutMs) : "Local worker exited before readiness")));
|
|
66163
66199
|
this.children.delete(child);
|
|
66164
66200
|
this.logs.delete(child);
|
|
@@ -66182,7 +66218,7 @@ class PoolCoordinator {
|
|
|
66182
66218
|
const held = slot.work;
|
|
66183
66219
|
if (held)
|
|
66184
66220
|
this.held.add(held.id);
|
|
66185
|
-
let
|
|
66221
|
+
let unconfirmed;
|
|
66186
66222
|
const cleanup = disconnected.then(() => serial).then(async () => {
|
|
66187
66223
|
try {
|
|
66188
66224
|
const admission = this.admission;
|
|
@@ -66195,18 +66231,13 @@ class PoolCoordinator {
|
|
|
66195
66231
|
throw unconfirmedCleanup(alive);
|
|
66196
66232
|
if (alive.length === 0)
|
|
66197
66233
|
return;
|
|
66198
|
-
|
|
66199
|
-
|
|
66200
|
-
this.quarantined.add(held.id);
|
|
66201
|
-
slot.work = undefined;
|
|
66202
|
-
childFailed = true;
|
|
66203
|
-
this.port.send({ kind: "work-failure", workId: held.id, error: error.message });
|
|
66204
|
-
}
|
|
66234
|
+
unconfirmed = unconfirmedCleanup(alive);
|
|
66235
|
+
this.reportHealth(logPath, `${unconfirmed.message}; the worker was retired and replaced`);
|
|
66205
66236
|
} catch (error) {
|
|
66206
66237
|
this.cleanupFailure = error instanceof Error ? error : new Error(String(error));
|
|
66207
66238
|
throw this.cleanupFailure;
|
|
66208
66239
|
} finally {
|
|
66209
|
-
if (held
|
|
66240
|
+
if (held)
|
|
66210
66241
|
this.held.delete(held.id);
|
|
66211
66242
|
}
|
|
66212
66243
|
}).then(async () => {
|
|
@@ -66227,8 +66258,8 @@ class PoolCoordinator {
|
|
|
66227
66258
|
const settled = attempt !== undefined && await this.whileRootLate(queue, () => exhausted ? queue.failExited(lease, attempt) : queue.releaseExited(lease, attempt));
|
|
66228
66259
|
const superseded = work !== undefined && !settled && await this.superseded(work);
|
|
66229
66260
|
if (work !== undefined && exhausted && !superseded)
|
|
66230
|
-
this.failWork(work, diagnosed(childRetryLimit(work, "lost its worker")));
|
|
66231
|
-
if (work === undefined &&
|
|
66261
|
+
this.failWork(work, diagnosed(`${childRetryLimit(work, "lost its worker")}${unconfirmed === undefined ? "" : `; ${unconfirmed.message}`}`));
|
|
66262
|
+
if (work === undefined && ++this.replacements > 3)
|
|
66232
66263
|
this.fail(diagnosed("Local worker retry limit"));
|
|
66233
66264
|
else
|
|
66234
66265
|
await this.spawn();
|
|
@@ -66237,7 +66268,9 @@ class PoolCoordinator {
|
|
|
66237
66268
|
});
|
|
66238
66269
|
this.cleanups.add(cleanup);
|
|
66239
66270
|
cleanup.finally(() => this.cleanups.delete(cleanup));
|
|
66240
|
-
}
|
|
66271
|
+
};
|
|
66272
|
+
slot.retire = retire;
|
|
66273
|
+
child.once("exit", retire);
|
|
66241
66274
|
child.on("message", (message) => {
|
|
66242
66275
|
this.observeResponsiveness();
|
|
66243
66276
|
this.lastHeard.set(worker, { at: performance.now(), stalled: this.stalledMs });
|
|
@@ -66311,10 +66344,11 @@ class PoolCoordinator {
|
|
|
66311
66344
|
const fenced = slot.work;
|
|
66312
66345
|
slot.work = undefined;
|
|
66313
66346
|
if (fenced && !await this.superseded(fenced)) {
|
|
66347
|
+
this.fence(fenced);
|
|
66314
66348
|
if (this.attempts(fenced) < MAX_CHILD_ATTEMPTS)
|
|
66315
66349
|
await leased(() => queue.releaseExited(lease, fenced));
|
|
66316
66350
|
else if (await leased(() => queue.failExited(lease, fenced)))
|
|
66317
|
-
this.failWork(fenced, new Error(childRetryLimit(fenced, "was refused by the root as stale on every attempt")));
|
|
66351
|
+
this.failWork(fenced, new Error(childRetryLimit(fenced, message.fault === undefined ? "was refused by the root as stale on every attempt" : `failed on a fault of the pool on every attempt (last: ${message.fault})`)));
|
|
66318
66352
|
}
|
|
66319
66353
|
return;
|
|
66320
66354
|
}
|
|
@@ -66475,8 +66509,6 @@ class PoolCoordinator {
|
|
|
66475
66509
|
return;
|
|
66476
66510
|
}
|
|
66477
66511
|
for (const work of expired) {
|
|
66478
|
-
if (this.quarantined.has(work.id))
|
|
66479
|
-
continue;
|
|
66480
66512
|
if (this.held.has(work.id)) {
|
|
66481
66513
|
await queue.extend(lease, work, leaseMs).catch((error) => {
|
|
66482
66514
|
if (error.message !== STALE_WORK_LEASE)
|
|
@@ -66492,9 +66524,9 @@ class PoolCoordinator {
|
|
|
66492
66524
|
});
|
|
66493
66525
|
continue;
|
|
66494
66526
|
}
|
|
66495
|
-
if (child && !await this.stop(child)
|
|
66496
|
-
|
|
66497
|
-
if (this.held.has(work.id)
|
|
66527
|
+
if (child && !await this.stop(child))
|
|
66528
|
+
this.retireUnconfirmed(child);
|
|
66529
|
+
if (this.held.has(work.id))
|
|
66498
66530
|
continue;
|
|
66499
66531
|
if ((await unconfirmedProcessGroups(this.journal, root, { attempt: work })).length > 0)
|
|
66500
66532
|
continue;
|
|
@@ -66521,17 +66553,49 @@ class PoolCoordinator {
|
|
|
66521
66553
|
const heard = this.lastHeard.get(worker);
|
|
66522
66554
|
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.stalledMs - heard.stalled) < this.options.leaseMs;
|
|
66523
66555
|
}
|
|
66524
|
-
stop(child) {
|
|
66525
|
-
|
|
66526
|
-
|
|
66527
|
-
|
|
66528
|
-
|
|
66529
|
-
|
|
66530
|
-
|
|
66531
|
-
|
|
66532
|
-
|
|
66533
|
-
|
|
66534
|
-
|
|
66556
|
+
async stop(child) {
|
|
66557
|
+
const pid = child.pid;
|
|
66558
|
+
const exited = () => child.exitCode !== null || child.signalCode !== null;
|
|
66559
|
+
if (pid === undefined || exited())
|
|
66560
|
+
return true;
|
|
66561
|
+
const exit = new Promise((resolve) => child.once("exit", () => resolve()));
|
|
66562
|
+
const confirmed = async () => {
|
|
66563
|
+
await Promise.race([exit, delay2(WORKER_EXIT_CONFIRMATION_MS)]);
|
|
66564
|
+
return true;
|
|
66565
|
+
};
|
|
66566
|
+
this.observeResponsiveness();
|
|
66567
|
+
child.kill("SIGKILL");
|
|
66568
|
+
const since = performance.now();
|
|
66569
|
+
const stalledAt = this.stalledMs;
|
|
66570
|
+
for (;; ) {
|
|
66571
|
+
await Promise.race([exit, delay2(WORKER_EXIT_POLL_MS)]);
|
|
66572
|
+
if (exited())
|
|
66573
|
+
return true;
|
|
66574
|
+
if (workerProcessExited(pid))
|
|
66575
|
+
return confirmed();
|
|
66576
|
+
this.observeResponsiveness();
|
|
66577
|
+
if (performance.now() - since - (this.stalledMs - stalledAt) >= WORKER_EXIT_CONFIRMATION_MS)
|
|
66578
|
+
return exited() || workerProcessExited(pid, true) && confirmed();
|
|
66579
|
+
}
|
|
66580
|
+
}
|
|
66581
|
+
retireUnconfirmed(child) {
|
|
66582
|
+
if (this.unconfirmedExits.has(child))
|
|
66583
|
+
return;
|
|
66584
|
+
this.unconfirmedExits.add(child);
|
|
66585
|
+
this.reportHealth(this.logs.get(child), `Local worker cleanup was not confirmed: worker process ${child.pid} was still running ${WORKER_EXIT_CONFIRMATION_MS} ms after SIGKILL; it was retired and replaced`);
|
|
66586
|
+
if (child.connected)
|
|
66587
|
+
child.disconnect();
|
|
66588
|
+
for (const slot of this.slots)
|
|
66589
|
+
if (slot.child === child)
|
|
66590
|
+
slot.retire?.();
|
|
66591
|
+
}
|
|
66592
|
+
reportHealth(log, message) {
|
|
66593
|
+
if (log !== undefined) {
|
|
66594
|
+
this.keptLogs.add(log);
|
|
66595
|
+
appendFile(log, `[atomic ${new Date().toISOString()}] ${message}
|
|
66596
|
+
`).catch(() => {});
|
|
66597
|
+
}
|
|
66598
|
+
this.port.send({ kind: "health", message: log === undefined ? message : `${message} (worker log: ${log})` });
|
|
66535
66599
|
}
|
|
66536
66600
|
async close() {
|
|
66537
66601
|
this.closed = true;
|
|
@@ -66541,10 +66605,15 @@ class PoolCoordinator {
|
|
|
66541
66605
|
this.rateLimitOutbox.close();
|
|
66542
66606
|
let failure;
|
|
66543
66607
|
let stopping = [];
|
|
66608
|
+
let confirmed = [];
|
|
66544
66609
|
try {
|
|
66545
66610
|
await this.recovering?.catch(() => {});
|
|
66546
66611
|
stopping = [...this.children].map((child) => ({ child, log: this.logs.get(child) }));
|
|
66547
|
-
await Promise.all(stopping.map(({ child }) => this.stop(child)));
|
|
66612
|
+
confirmed = await Promise.all(stopping.map(({ child }) => this.stop(child)));
|
|
66613
|
+
stopping.forEach(({ child }, index) => {
|
|
66614
|
+
if (!confirmed[index])
|
|
66615
|
+
this.retireUnconfirmed(child);
|
|
66616
|
+
});
|
|
66548
66617
|
await Promise.all([...this.cleanups]);
|
|
66549
66618
|
if (this.cleanupFailure)
|
|
66550
66619
|
throw this.cleanupFailure;
|
|
@@ -66556,15 +66625,15 @@ class PoolCoordinator {
|
|
|
66556
66625
|
if (alive.length > 0)
|
|
66557
66626
|
throw unconfirmedCleanup(alive);
|
|
66558
66627
|
if (this.desiredControl !== "quit" && this.queue !== undefined && this.lease !== undefined)
|
|
66559
|
-
await this.queue.releaseClosed(this.lease
|
|
66628
|
+
await this.queue.releaseClosed(this.lease).catch((error) => {
|
|
66560
66629
|
if (!(error instanceof StaleLeaseError))
|
|
66561
66630
|
throw error;
|
|
66562
66631
|
});
|
|
66563
66632
|
} catch (error) {
|
|
66564
66633
|
failure = error;
|
|
66565
66634
|
}
|
|
66566
|
-
if (failure === undefined) {
|
|
66567
|
-
const stopped = stopping.flatMap(({
|
|
66635
|
+
if (failure === undefined && !this.failed) {
|
|
66636
|
+
const stopped = stopping.flatMap(({ log }, index) => log !== undefined && !this.keptLogs.has(log) && confirmed[index] === true ? [log] : []);
|
|
66568
66637
|
await Promise.all(stopped.map((log) => rm3(log, { force: true }).catch(() => {})));
|
|
66569
66638
|
if (this.logDirectory !== undefined)
|
|
66570
66639
|
await rmdir(this.logDirectory).catch(() => {});
|
|
@@ -66616,7 +66685,7 @@ function runPoolCoordinator() {
|
|
|
66616
66685
|
port.onClose(() => process.exit(0));
|
|
66617
66686
|
return coordinator;
|
|
66618
66687
|
}
|
|
66619
|
-
var CONTROL_ACKNOWLEDGEMENT_STALL_MS = 5000, RECOVERY_INTERVAL_MS = 500, TICK_INTERVAL_MS = 100, STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, LATE_ROOT_POLL_MS, MIRROR_INTERVAL_MS = 1e4, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000, MAX_CHILD_ATTEMPTS = 3, ROUTE_REGISTRATION_WAIT_MS = 120000, STAGE_WATCH_BACKLOG_EVENTS = 2000, STAGE_WATCH_BACKLOG_BYTES, PENDING_STAGE_MESSAGE_EVENT2 = "atomic:workflow-pending-stage-message", STICKY_LIVE_DELIVERED_EVENT2 = "atomic:workflow-sticky-live-delivered", PENDING_STAGE_UNDELIVERABLE_EVENT2 = "atomic:workflow-pending-stage-undeliverable", ENDED_WATCHES_REMEMBERED = 1024;
|
|
66688
|
+
var CONTROL_ACKNOWLEDGEMENT_STALL_MS = 5000, RECOVERY_INTERVAL_MS = 500, TICK_INTERVAL_MS = 100, STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, LATE_ROOT_POLL_MS, MIRROR_INTERVAL_MS = 1e4, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000, WORKER_EXIT_CONFIRMATION_MS = 5000, WORKER_EXIT_POLL_MS = 50, MAX_CHILD_ATTEMPTS = 3, ROUTE_REGISTRATION_WAIT_MS = 120000, STAGE_WATCH_BACKLOG_EVENTS = 2000, STAGE_WATCH_BACKLOG_BYTES, PENDING_STAGE_MESSAGE_EVENT2 = "atomic:workflow-pending-stage-message", STICKY_LIVE_DELIVERED_EVENT2 = "atomic:workflow-sticky-live-delivered", PENDING_STAGE_UNDELIVERABLE_EVENT2 = "atomic:workflow-pending-stage-undeliverable", ENDED_WATCHES_REMEMBERED = 1024;
|
|
66620
66689
|
var init_pool_coordinator = __esm(() => {
|
|
66621
66690
|
init_internal();
|
|
66622
66691
|
init_pool_remote_journal();
|
|
@@ -66631,6 +66700,7 @@ var init_pool_coordinator = __esm(() => {
|
|
|
66631
66700
|
init_pending_stage_route_readiness();
|
|
66632
66701
|
init_store();
|
|
66633
66702
|
init_workflow_infrastructure_error();
|
|
66703
|
+
init_admission_host();
|
|
66634
66704
|
init_pool_journal();
|
|
66635
66705
|
init_pooled_watch_trace();
|
|
66636
66706
|
init_resource_admission();
|
|
@@ -68581,6 +68651,7 @@ class LocalWorkerPool {
|
|
|
68581
68651
|
works = new Map;
|
|
68582
68652
|
attempts = new Map;
|
|
68583
68653
|
results = new Map;
|
|
68654
|
+
healthEvents = [];
|
|
68584
68655
|
workFailures = new Map;
|
|
68585
68656
|
changed = Promise.withResolvers();
|
|
68586
68657
|
waiting = 0;
|
|
@@ -68638,6 +68709,9 @@ class LocalWorkerPool {
|
|
|
68638
68709
|
if (options.admission && options.rootId === undefined)
|
|
68639
68710
|
workflowResourceAdmission.set(backend, options.admission);
|
|
68640
68711
|
}
|
|
68712
|
+
get health() {
|
|
68713
|
+
return this.healthEvents;
|
|
68714
|
+
}
|
|
68641
68715
|
get workerPids() {
|
|
68642
68716
|
return [...this.pids];
|
|
68643
68717
|
}
|
|
@@ -69231,14 +69305,8 @@ class LocalWorkerPool {
|
|
|
69231
69305
|
try {
|
|
69232
69306
|
return await this.dispatch(definition, inputs, options);
|
|
69233
69307
|
} catch (error) {
|
|
69234
|
-
if (
|
|
69235
|
-
|
|
69236
|
-
try {
|
|
69237
|
-
if (this.desiredControl !== "quit" || !findWorkflowGracefulQuit(error))
|
|
69238
|
-
await this.shutdown();
|
|
69239
|
-
} catch (closeError) {
|
|
69240
|
-
throw asWorkflowInfrastructureError(closeError) ?? closeError;
|
|
69241
|
-
}
|
|
69308
|
+
if (this.failure !== undefined || this.coordinatorLost !== undefined)
|
|
69309
|
+
await this.shutdown().catch(() => {});
|
|
69242
69310
|
throw asWorkflowInfrastructureError(error) ?? error;
|
|
69243
69311
|
}
|
|
69244
69312
|
}
|
|
@@ -69306,8 +69374,13 @@ class LocalWorkerPool {
|
|
|
69306
69374
|
try {
|
|
69307
69375
|
for (;; ) {
|
|
69308
69376
|
options.signal?.throwIfAborted();
|
|
69309
|
-
if (this.closed)
|
|
69310
|
-
|
|
69377
|
+
if (!this.results.has(work.id) && (this.closed || this.failure !== undefined)) {
|
|
69378
|
+
const recorded = await this.queue?.result(root, work.id).catch(() => {
|
|
69379
|
+
return;
|
|
69380
|
+
});
|
|
69381
|
+
if (recorded !== undefined)
|
|
69382
|
+
this.results.set(work.id, recorded);
|
|
69383
|
+
}
|
|
69311
69384
|
const result = this.results.get(work.id);
|
|
69312
69385
|
if (result) {
|
|
69313
69386
|
this.completing++;
|
|
@@ -69331,6 +69404,8 @@ class LocalWorkerPool {
|
|
|
69331
69404
|
this.endFailedChild(work, failed);
|
|
69332
69405
|
throw failed;
|
|
69333
69406
|
}
|
|
69407
|
+
if (this.closed)
|
|
69408
|
+
throw this.closedError(root);
|
|
69334
69409
|
if (this.failure)
|
|
69335
69410
|
throw this.failure;
|
|
69336
69411
|
if (this.budgetBlocked)
|
|
@@ -69365,6 +69440,19 @@ class LocalWorkerPool {
|
|
|
69365
69440
|
if (this.reconnectingViews.size > 0 || this.outboxes.size > 0)
|
|
69366
69441
|
this.reconnectStageViews();
|
|
69367
69442
|
}
|
|
69443
|
+
recordHealth(message) {
|
|
69444
|
+
this.healthEvents.push(message);
|
|
69445
|
+
const root = this.root;
|
|
69446
|
+
if (root === undefined || this.store === undefined)
|
|
69447
|
+
return;
|
|
69448
|
+
this.store.recordNotice({
|
|
69449
|
+
id: `local-worker-health:${root}:${this.healthEvents.length}`,
|
|
69450
|
+
runId: root,
|
|
69451
|
+
level: "warning",
|
|
69452
|
+
message: `Local worker pool: ${message}`,
|
|
69453
|
+
createdAt: Date.now()
|
|
69454
|
+
});
|
|
69455
|
+
}
|
|
69368
69456
|
evaluateBudget() {
|
|
69369
69457
|
const decision = this.rootBudget?.checkpoint();
|
|
69370
69458
|
const blocked = decision?.kind === "exhausted" || decision?.kind === "wrap_up";
|
|
@@ -69483,6 +69571,9 @@ class LocalWorkerPool {
|
|
|
69483
69571
|
this.failure ??= new Error(event.error);
|
|
69484
69572
|
this.signalChange();
|
|
69485
69573
|
return;
|
|
69574
|
+
case "health":
|
|
69575
|
+
this.recordHealth(event.message);
|
|
69576
|
+
return;
|
|
69486
69577
|
case "stage-events":
|
|
69487
69578
|
this.stageWatches.get(event.watch)?.({ kind: "events", events: event.events });
|
|
69488
69579
|
this.notice({ kind: "stage-events-applied", watch: event.watch });
|
|
@@ -81314,6 +81405,7 @@ async function runWorker(start) {
|
|
|
81314
81405
|
await reader.catchUpWorkflow(start.root);
|
|
81315
81406
|
const work = await request({ kind: "claim" });
|
|
81316
81407
|
attemptFenced = false;
|
|
81408
|
+
let poolFault;
|
|
81317
81409
|
if (!work) {
|
|
81318
81410
|
await delay4(25 + Math.random() * 25);
|
|
81319
81411
|
continue;
|
|
@@ -81486,6 +81578,11 @@ async function runWorker(start) {
|
|
|
81486
81578
|
}
|
|
81487
81579
|
if (attemptFenced)
|
|
81488
81580
|
throw new WorkAttemptFencedError("Work attempt fenced before completion");
|
|
81581
|
+
if (failedOnInfrastructureFault(result)) {
|
|
81582
|
+
poolFault = infrastructureFaultMessage(result);
|
|
81583
|
+
attemptFenced = true;
|
|
81584
|
+
throw new WorkAttemptFencedError(poolFault);
|
|
81585
|
+
}
|
|
81489
81586
|
await request({ kind: "complete", result });
|
|
81490
81587
|
} catch (error) {
|
|
81491
81588
|
if (!attemptFenced)
|
|
@@ -81503,7 +81600,7 @@ async function runWorker(start) {
|
|
|
81503
81600
|
await renewal;
|
|
81504
81601
|
await report;
|
|
81505
81602
|
await controlPulse;
|
|
81506
|
-
await request({ kind: "fenced" });
|
|
81603
|
+
await request({ kind: "fenced", ...poolFault === undefined ? {} : { fault: poolFault } });
|
|
81507
81604
|
}
|
|
81508
81605
|
if (rootLeaseLost)
|
|
81509
81606
|
break;
|