@bastani/atomic 0.9.42 → 0.9.43
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 +38 -0
- package/dist/builtin/intercom/CHANGELOG.md +12 -0
- package/dist/builtin/intercom/index.bundle.mjs +20 -12
- 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/CHANGELOG.md +38 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/authoring.d.ts +2 -0
- package/dist/builtin/workflows/src/durable/journal/internal.d.ts +17 -1
- package/dist/builtin/workflows/src/durable/journal/sql-run-journal.d.ts +5 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +363 -90
- package/dist/builtin/workflows/src/extension/local-worker-entry.mjs +444 -180
- package/dist/builtin/workflows/src/index.js +334 -69
- package/dist/builtin/workflows/src/local-worker-entry.mjs +444 -180
- package/dist/builtin/workflows/src/shared/workflow-infrastructure-error.d.ts +10 -0
- package/dist/builtin/workflows/src/workers/public-options.d.ts +2 -0
- package/dist/core/settings-schema.d.ts +2 -0
- package/dist/core/settings-schema.d.ts.map +1 -1
- package/dist/core/settings-schema.js +10 -0
- package/dist/core/settings-schema.js.map +1 -1
- package/docs/settings.md +4 -0
- package/docs/workflows/api-reference.md +18 -3
- package/docs/workflows/operations.md +11 -1
- package/npm-shrinkwrap.json +32 -32
- package/package.json +3 -3
- package/schemas/settings.schema.json +12 -0
|
@@ -989,8 +989,14 @@ function registerSqlPoolStorage(journal, storage) {
|
|
|
989
989
|
function sqlPoolStorage(journal) {
|
|
990
990
|
return poolStorage.get(journal);
|
|
991
991
|
}
|
|
992
|
-
var JOURNAL_READ_PAGE_SIZE = 256, versionReaders, poolStorage;
|
|
992
|
+
var JOURNAL_READ_PAGE_SIZE = 256, NON_SNAPSHOT_EVENT_TYPES, versionReaders, poolStorage;
|
|
993
993
|
var init_internal = __esm(() => {
|
|
994
|
+
init_types();
|
|
995
|
+
NON_SNAPSHOT_EVENT_TYPES = [
|
|
996
|
+
RUN_EVENT_TYPES.checkpointRecorded,
|
|
997
|
+
RUN_EVENT_TYPES.messageSettled,
|
|
998
|
+
RUN_EVENT_TYPES.messageDelivered
|
|
999
|
+
];
|
|
994
1000
|
versionReaders = new WeakMap;
|
|
995
1001
|
poolStorage = new WeakMap;
|
|
996
1002
|
});
|
|
@@ -1372,7 +1378,8 @@ class SqlRunJournal {
|
|
|
1372
1378
|
this.legacy = legacy;
|
|
1373
1379
|
registerRunJournalVersions(this, {
|
|
1374
1380
|
changeToken: () => this.changeToken(),
|
|
1375
|
-
runVersions: () => this.runVersions()
|
|
1381
|
+
runVersions: () => this.runVersions(),
|
|
1382
|
+
snapshotTail: (runId) => this.snapshotTail(runId)
|
|
1376
1383
|
});
|
|
1377
1384
|
registerSqlPoolStorage(this, {
|
|
1378
1385
|
transaction: (body) => this.operation(() => this.database.transaction(body)),
|
|
@@ -1498,6 +1505,28 @@ class SqlRunJournal {
|
|
|
1498
1505
|
]));
|
|
1499
1506
|
});
|
|
1500
1507
|
}
|
|
1508
|
+
async snapshotTail(runId) {
|
|
1509
|
+
this.assertOpen();
|
|
1510
|
+
validateText("runId", runId);
|
|
1511
|
+
return this.operation(async () => {
|
|
1512
|
+
const events = await this.isUnconvertedLegacyRun(runId) ? JOURNAL_TABLES.events : this.tables.events;
|
|
1513
|
+
const later = `FROM ${events} AS later WHERE later.${JOURNAL_COLUMNS.runId} = snapshot.${JOURNAL_COLUMNS.runId} AND later.${JOURNAL_COLUMNS.seq} > snapshot.${JOURNAL_COLUMNS.seq} AND later.${JOURNAL_COLUMNS.type} = ?`;
|
|
1514
|
+
const row = await this.database.get(`SELECT ${EVENT_COLUMNS.map((column) => `snapshot.${column}`).join(", ")},
|
|
1515
|
+
latest.${JOURNAL_COLUMNS.seq} AS latest_seq, latest.${JOURNAL_COLUMNS.at} AS latest_at,
|
|
1516
|
+
(SELECT count(*) ${later}) AS later_checkpoints,
|
|
1517
|
+
(SELECT json_extract(later.${JOURNAL_COLUMNS.payload}, '$.completedAt') ${later} ORDER BY later.${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS last_checkpoint_at
|
|
1518
|
+
FROM (SELECT ${JOURNAL_COLUMNS.seq}, ${JOURNAL_COLUMNS.at} FROM ${events} WHERE ${JOURNAL_COLUMNS.runId} = ? ORDER BY ${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS latest,
|
|
1519
|
+
(SELECT ${EVENT_COLUMNS.join(", ")} FROM ${events} WHERE ${JOURNAL_COLUMNS.runId} = ? AND ${JOURNAL_COLUMNS.type} NOT IN (${NON_SNAPSHOT_EVENT_TYPES.map(() => "?").join(", ")}) ORDER BY ${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS snapshot`, RUN_EVENT_TYPES.checkpointRecorded, RUN_EVENT_TYPES.checkpointRecorded, runId, runId, ...NON_SNAPSHOT_EVENT_TYPES);
|
|
1520
|
+
if (row === undefined)
|
|
1521
|
+
return;
|
|
1522
|
+
return {
|
|
1523
|
+
version: { seq: journalCounter(runId, "seq", row.latest_seq), at: Number(row.latest_at) },
|
|
1524
|
+
snapshot: entryFromRow(row),
|
|
1525
|
+
laterCheckpoints: Number(row.later_checkpoints),
|
|
1526
|
+
...row.last_checkpoint_at === null ? {} : { lastCheckpointAt: Number(row.last_checkpoint_at) }
|
|
1527
|
+
};
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1501
1530
|
async requireRun(tx, runId) {
|
|
1502
1531
|
if (await tx.get(`SELECT ${JOURNAL_COLUMNS.runId} FROM ${this.tables.runs} WHERE ${JOURNAL_COLUMNS.runId} = ?`, runId))
|
|
1503
1532
|
return;
|
|
@@ -1715,13 +1744,14 @@ class SqlRunJournal {
|
|
|
1715
1744
|
return this.closePromise;
|
|
1716
1745
|
}
|
|
1717
1746
|
}
|
|
1718
|
-
var STORE_NOW = "CAST(unixepoch('subsec') * 1000 AS INTEGER)";
|
|
1747
|
+
var STORE_NOW = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", EVENT_COLUMNS;
|
|
1719
1748
|
var init_sql_run_journal = __esm(() => {
|
|
1720
1749
|
init_internal();
|
|
1721
1750
|
init_legacy_journal_tables();
|
|
1722
1751
|
init_types();
|
|
1723
1752
|
init_values();
|
|
1724
1753
|
init_internal();
|
|
1754
|
+
EVENT_COLUMNS = [JOURNAL_COLUMNS.runId, JOURNAL_COLUMNS.seq, JOURNAL_COLUMNS.epoch, JOURNAL_COLUMNS.key, JOURNAL_COLUMNS.type, JOURNAL_COLUMNS.payload, JOURNAL_COLUMNS.at];
|
|
1725
1755
|
});
|
|
1726
1756
|
|
|
1727
1757
|
// dist/builtin/workflows/src/durable/journal/resolution.ts
|
|
@@ -9853,6 +9883,7 @@ class JournalDurableBackend {
|
|
|
9853
9883
|
projection = createJournalProjection();
|
|
9854
9884
|
sequences = new Map;
|
|
9855
9885
|
foldedAt = new Map;
|
|
9886
|
+
summarized = new Map;
|
|
9856
9887
|
catalogToken;
|
|
9857
9888
|
leases = new Map;
|
|
9858
9889
|
executions = new Map;
|
|
@@ -9878,8 +9909,8 @@ class JournalDurableBackend {
|
|
|
9878
9909
|
let backend;
|
|
9879
9910
|
try {
|
|
9880
9911
|
backend = new JournalDurableBackend(journal, undefined, options.ownsJournal ?? true);
|
|
9881
|
-
for (const
|
|
9882
|
-
for await (const entry of journal.read(
|
|
9912
|
+
for (const runId of options.runs ?? (await journal.listRuns()).map((run) => run.runId))
|
|
9913
|
+
for await (const entry of journal.read(runId))
|
|
9883
9914
|
backend.fold(entry);
|
|
9884
9915
|
return backend;
|
|
9885
9916
|
} catch (error) {
|
|
@@ -9952,6 +9983,18 @@ class JournalDurableBackend {
|
|
|
9952
9983
|
this.sequences.set(entry.runId, entry.seq);
|
|
9953
9984
|
this.foldedAt.set(entry.runId, entry.at);
|
|
9954
9985
|
}
|
|
9986
|
+
summarize(runId, tail) {
|
|
9987
|
+
const event = tail.snapshot.event;
|
|
9988
|
+
const handle = event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased ? event.payload.handle : event.payload;
|
|
9989
|
+
this.projection.deleteWorkflow(runId);
|
|
9990
|
+
this.prompts.delete(runId);
|
|
9991
|
+
this.projection.applyWorkflowSnapshot({
|
|
9992
|
+
...handle,
|
|
9993
|
+
completedCheckpoints: handle.completedCheckpoints + tail.laterCheckpoints,
|
|
9994
|
+
...tail.lastCheckpointAt === undefined ? {} : { updatedAt: tail.lastCheckpointAt }
|
|
9995
|
+
});
|
|
9996
|
+
this.summarized.set(runId, tail.version);
|
|
9997
|
+
}
|
|
9955
9998
|
*entries(runId, fromSeq) {
|
|
9956
9999
|
return yield* invoke(async () => {
|
|
9957
10000
|
const entries = [];
|
|
@@ -9965,6 +10008,7 @@ class JournalDurableBackend {
|
|
|
9965
10008
|
this.projection.deleteWorkflow(runId);
|
|
9966
10009
|
this.sequences.delete(runId);
|
|
9967
10010
|
this.foldedAt.delete(runId);
|
|
10011
|
+
this.summarized.delete(runId);
|
|
9968
10012
|
this.prompts.delete(runId);
|
|
9969
10013
|
for (const entry of entries)
|
|
9970
10014
|
this.fold(entry);
|
|
@@ -10286,6 +10330,9 @@ class JournalDurableBackend {
|
|
|
10286
10330
|
async hydrateWorkflow(runId) {
|
|
10287
10331
|
await this.serialize(runId, () => this.rebuild(runId), false);
|
|
10288
10332
|
}
|
|
10333
|
+
async catchUpWorkflow(runId) {
|
|
10334
|
+
await this.serialize(runId, () => this.extend(runId), false);
|
|
10335
|
+
}
|
|
10289
10336
|
hydrateResumableWorkflows() {
|
|
10290
10337
|
return this.serialize(this.catalogQueue, () => invoke(async () => {
|
|
10291
10338
|
const journal = runJournalVersions(this.journal);
|
|
@@ -10299,16 +10346,33 @@ class JournalDurableBackend {
|
|
|
10299
10346
|
if (token === this.catalogToken)
|
|
10300
10347
|
return;
|
|
10301
10348
|
const versions = await journal.runVersions();
|
|
10302
|
-
for (const runId of new Set([...this.sequences.keys(), ...versions.keys()]))
|
|
10303
|
-
await this.serialize(runId, () => this.catchUp(runId, versions.get(runId)), false);
|
|
10349
|
+
for (const runId of new Set([...this.sequences.keys(), ...this.summarized.keys(), ...versions.keys()]))
|
|
10350
|
+
await this.serialize(runId, () => this.catchUp(runId, versions.get(runId), journal), false);
|
|
10304
10351
|
this.catalogToken = token;
|
|
10305
10352
|
}));
|
|
10306
10353
|
}
|
|
10307
|
-
*catchUp(runId, version) {
|
|
10354
|
+
*catchUp(runId, version, journal) {
|
|
10308
10355
|
const folded = this.sequences.get(runId) ?? 0;
|
|
10356
|
+
if (folded === 0 && version !== undefined) {
|
|
10357
|
+
const summarized = this.summarized.get(runId);
|
|
10358
|
+
if (summarized !== undefined && summarized.seq === version.seq && summarized.at === version.at)
|
|
10359
|
+
return;
|
|
10360
|
+
const tail = yield* invoke(() => journal.snapshotTail(runId));
|
|
10361
|
+
if (tail !== undefined)
|
|
10362
|
+
return this.summarize(runId, tail);
|
|
10363
|
+
if (summarized === undefined && version.seq === 0)
|
|
10364
|
+
return;
|
|
10365
|
+
return yield* this.rebuild(runId);
|
|
10366
|
+
}
|
|
10309
10367
|
if (version !== undefined && version.seq === folded && version.at === (this.foldedAt.get(runId) ?? 0))
|
|
10310
10368
|
return;
|
|
10311
|
-
if (version !== undefined && folded > 0 && version.seq > folded)
|
|
10369
|
+
if (version !== undefined && folded > 0 && version.seq > folded)
|
|
10370
|
+
return yield* this.extend(runId);
|
|
10371
|
+
yield* this.rebuild(runId);
|
|
10372
|
+
}
|
|
10373
|
+
*extend(runId) {
|
|
10374
|
+
const folded = this.sequences.get(runId) ?? 0;
|
|
10375
|
+
if (folded > 0) {
|
|
10312
10376
|
const entries = yield* this.entries(runId, folded);
|
|
10313
10377
|
if (entries[0]?.seq === folded && entries[0].at === this.foldedAt.get(runId)) {
|
|
10314
10378
|
for (const entry of entries)
|
|
@@ -10336,6 +10400,7 @@ class JournalDurableBackend {
|
|
|
10336
10400
|
this.leases.delete(runId);
|
|
10337
10401
|
this.sequences.delete(runId);
|
|
10338
10402
|
this.foldedAt.delete(runId);
|
|
10403
|
+
this.summarized.delete(runId);
|
|
10339
10404
|
this.prompts.delete(runId);
|
|
10340
10405
|
this.projection.deleteWorkflow(runId);
|
|
10341
10406
|
}
|
|
@@ -10600,7 +10665,13 @@ async function initializeDurableBackend(options = {}) {
|
|
|
10600
10665
|
const selected = owner.selectedBackends;
|
|
10601
10666
|
const existing = selected.get(key);
|
|
10602
10667
|
const entry = existing ?? {
|
|
10603
|
-
ready: openSelectedRunJournal(selection, agentDir).then((journal) => JournalDurableBackend.open(journal, { ownsJournal })).then((opened) => {
|
|
10668
|
+
ready: openSelectedRunJournal(selection, agentDir).then((journal) => JournalDurableBackend.open(journal, { ownsJournal, runs: [] })).then(async (opened) => {
|
|
10669
|
+
try {
|
|
10670
|
+
await opened.hydrateResumableWorkflows();
|
|
10671
|
+
} catch (error) {
|
|
10672
|
+
await opened.close();
|
|
10673
|
+
throw error;
|
|
10674
|
+
}
|
|
10604
10675
|
if (ownsJournal)
|
|
10605
10676
|
opened.closeOnProcessExit();
|
|
10606
10677
|
entry.close = () => opened.close();
|
|
@@ -57495,7 +57566,7 @@ class SqlPoolQueue {
|
|
|
57495
57566
|
});
|
|
57496
57567
|
const row = await this.current(tx, lease, token);
|
|
57497
57568
|
if (row.epoch !== lease.epoch || row.expires_at < now)
|
|
57498
|
-
throw new Error(
|
|
57569
|
+
throw new Error(STALE_WORK_LEASE);
|
|
57499
57570
|
assertSession();
|
|
57500
57571
|
}, action);
|
|
57501
57572
|
}
|
|
@@ -57504,7 +57575,7 @@ class SqlPoolQueue {
|
|
|
57504
57575
|
const { now } = await this.authority(tx, lease);
|
|
57505
57576
|
const row = await this.current(tx, lease, token);
|
|
57506
57577
|
if (row.epoch !== lease.epoch || row.expires_at < now)
|
|
57507
|
-
throw new Error(
|
|
57578
|
+
throw new Error(STALE_WORK_LEASE);
|
|
57508
57579
|
});
|
|
57509
57580
|
}
|
|
57510
57581
|
async enqueue(lease, descriptor, boundary) {
|
|
@@ -57584,7 +57655,7 @@ class SqlPoolQueue {
|
|
|
57584
57655
|
async current(tx, lease, token, allowCompleted = false) {
|
|
57585
57656
|
const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, token.id, lease.runId);
|
|
57586
57657
|
if (row?.state !== "leased" && !(allowCompleted && row?.state === "completed") || row.epoch !== token.epoch || row.generation !== token.generation || row.worker !== token.worker)
|
|
57587
|
-
throw new Error(
|
|
57658
|
+
throw new Error(STALE_WORK_LEASE);
|
|
57588
57659
|
return row;
|
|
57589
57660
|
}
|
|
57590
57661
|
async renew(lease, token, operationId, durationMs) {
|
|
@@ -57597,7 +57668,7 @@ class SqlPoolQueue {
|
|
|
57597
57668
|
const { now } = await this.authority(tx, lease);
|
|
57598
57669
|
const row = await this.current(tx, lease, token);
|
|
57599
57670
|
if (row.epoch !== lease.epoch || row.expires_at < now)
|
|
57600
|
-
throw new Error(
|
|
57671
|
+
throw new Error(STALE_WORK_LEASE);
|
|
57601
57672
|
const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
57602
57673
|
if (previous) {
|
|
57603
57674
|
if (previous.request !== request)
|
|
@@ -57625,7 +57696,7 @@ class SqlPoolQueue {
|
|
|
57625
57696
|
const { now, status } = await this.authority(tx, lease);
|
|
57626
57697
|
const row = await this.current(tx, lease, token);
|
|
57627
57698
|
if (row.epoch !== lease.epoch)
|
|
57628
|
-
throw new Error(
|
|
57699
|
+
throw new Error(STALE_WORK_LEASE);
|
|
57629
57700
|
const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
57630
57701
|
if (previous) {
|
|
57631
57702
|
if (previous.request !== request)
|
|
@@ -57633,7 +57704,7 @@ class SqlPoolQueue {
|
|
|
57633
57704
|
return JSON.parse(previous.receipt);
|
|
57634
57705
|
}
|
|
57635
57706
|
if (row.expires_at < now)
|
|
57636
|
-
throw new Error(
|
|
57707
|
+
throw new Error(STALE_WORK_LEASE);
|
|
57637
57708
|
if (!await this.admitsAttemptWrites(tx, lease, status))
|
|
57638
57709
|
throw new Error("Pool root is not running");
|
|
57639
57710
|
const checkpoint = mutation.checkpoint;
|
|
@@ -57673,7 +57744,7 @@ class SqlPoolQueue {
|
|
|
57673
57744
|
const { now, status } = await this.authority(tx, lease);
|
|
57674
57745
|
const row = await this.current(tx, lease, token, true);
|
|
57675
57746
|
if (row.epoch !== lease.epoch)
|
|
57676
|
-
throw new Error(
|
|
57747
|
+
throw new Error(STALE_WORK_LEASE);
|
|
57677
57748
|
if (row.state === "completed") {
|
|
57678
57749
|
const previous = await tx.get(`SELECT result FROM ${this.work}_results WHERE work = ?`, token.id);
|
|
57679
57750
|
if (previous?.result !== payload)
|
|
@@ -57681,7 +57752,7 @@ class SqlPoolQueue {
|
|
|
57681
57752
|
return;
|
|
57682
57753
|
}
|
|
57683
57754
|
if (row.expires_at < now || !await this.admitsAttemptWrites(tx, lease, status))
|
|
57684
|
-
throw new Error(
|
|
57755
|
+
throw new Error(STALE_WORK_LEASE);
|
|
57685
57756
|
if (JSON.parse(payload).runId !== fromRow(row).childRunId)
|
|
57686
57757
|
throw new Error("Pool result identity mismatch");
|
|
57687
57758
|
await tx.run(`INSERT INTO ${this.work}_results VALUES (?, ?)`, token.id, payload);
|
|
@@ -57706,6 +57777,40 @@ class SqlPoolQueue {
|
|
|
57706
57777
|
return true;
|
|
57707
57778
|
});
|
|
57708
57779
|
}
|
|
57780
|
+
async extend(lease, token, durationMs) {
|
|
57781
|
+
positive(durationMs);
|
|
57782
|
+
lease = snapshotLease(lease);
|
|
57783
|
+
token = { ...token };
|
|
57784
|
+
return this.transaction(async (tx) => {
|
|
57785
|
+
const { now } = await this.authority(tx, lease);
|
|
57786
|
+
const row = await this.current(tx, lease, token);
|
|
57787
|
+
if (row.epoch !== lease.epoch)
|
|
57788
|
+
throw new Error(STALE_WORK_LEASE);
|
|
57789
|
+
const expiresAt = Math.max(Number(row.expires_at), expiry(now, durationMs));
|
|
57790
|
+
await tx.run(`UPDATE ${this.work} SET expires_at = ?, renewed_at = ? WHERE id = ?`, expiresAt, now, row.id);
|
|
57791
|
+
return { ...fromRow(row), expiresAt, renewedAt: now };
|
|
57792
|
+
});
|
|
57793
|
+
}
|
|
57794
|
+
async releaseExited(lease, token) {
|
|
57795
|
+
lease = snapshotLease(lease);
|
|
57796
|
+
token = { ...token };
|
|
57797
|
+
return this.transaction(async (tx) => {
|
|
57798
|
+
await this.authority(tx, lease);
|
|
57799
|
+
const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, token.id, lease.runId);
|
|
57800
|
+
if (row?.state !== "leased" || row.generation !== token.generation || row.worker !== token.worker || row.epoch !== token.epoch)
|
|
57801
|
+
return false;
|
|
57802
|
+
await tx.run(`UPDATE ${this.work} SET state = 'ready', worker = NULL, expires_at = 0 WHERE id = ?`, row.id);
|
|
57803
|
+
return true;
|
|
57804
|
+
});
|
|
57805
|
+
}
|
|
57806
|
+
async releasePreviousIncarnations(lease) {
|
|
57807
|
+
lease = snapshotLease(lease);
|
|
57808
|
+
return this.transaction(async (tx) => {
|
|
57809
|
+
await this.authority(tx, lease);
|
|
57810
|
+
const released = await tx.run(`UPDATE ${this.work} SET state = 'ready', worker = NULL, expires_at = 0 WHERE root = ? AND state = 'leased' AND epoch < ?`, lease.runId, lease.epoch);
|
|
57811
|
+
return released.changes;
|
|
57812
|
+
});
|
|
57813
|
+
}
|
|
57709
57814
|
async inspect(root) {
|
|
57710
57815
|
return this.transaction(async (tx) => (await tx.all(`SELECT * FROM ${this.work} WHERE root = ? ORDER BY ready_at, rowid`, root)).map(fromRow));
|
|
57711
57816
|
}
|
|
@@ -57716,7 +57821,7 @@ function openSqlPoolQueue(journal) {
|
|
|
57716
57821
|
return Promise.reject(new Error("Worker pool requires a SQL run journal"));
|
|
57717
57822
|
return SqlPoolQueue.open(storage);
|
|
57718
57823
|
}
|
|
57719
|
-
var STORE_NOW2 = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", MAX_WORKER_CLOCK_SKEW_MS = 1000;
|
|
57824
|
+
var STORE_NOW2 = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", MAX_WORKER_CLOCK_SKEW_MS = 1000, STALE_WORK_LEASE = "Stale work lease";
|
|
57720
57825
|
var init_sql_pool_queue = __esm(() => {
|
|
57721
57826
|
init_serializable();
|
|
57722
57827
|
init_boundary_topology();
|
|
@@ -61157,12 +61262,66 @@ var init_sdk_intercom = __esm(() => {
|
|
|
61157
61262
|
owners2 = new WeakMap;
|
|
61158
61263
|
});
|
|
61159
61264
|
|
|
61265
|
+
// dist/builtin/workflows/src/shared/workflow-infrastructure-error.ts
|
|
61266
|
+
function isInfrastructureError(value2) {
|
|
61267
|
+
if (value2 instanceof WorkflowInfrastructureError)
|
|
61268
|
+
return true;
|
|
61269
|
+
if (typeof value2 !== "object" || value2 === null)
|
|
61270
|
+
return false;
|
|
61271
|
+
const candidate = value2;
|
|
61272
|
+
return candidate.name === WORKFLOW_INFRASTRUCTURE_ERROR_NAME && candidate.retryable === true && typeof candidate.code === "string";
|
|
61273
|
+
}
|
|
61274
|
+
function isRetryableWorkflowError(error) {
|
|
61275
|
+
let current = error;
|
|
61276
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null; depth++) {
|
|
61277
|
+
if (isInfrastructureError(current))
|
|
61278
|
+
return true;
|
|
61279
|
+
current = current instanceof Error ? current.cause : undefined;
|
|
61280
|
+
}
|
|
61281
|
+
return false;
|
|
61282
|
+
}
|
|
61283
|
+
function workflowInfrastructureFault(message) {
|
|
61284
|
+
return FAULT_PATTERNS.find(([pattern]) => pattern.test(message))?.[1];
|
|
61285
|
+
}
|
|
61286
|
+
function asWorkflowInfrastructureError(error) {
|
|
61287
|
+
if (isInfrastructureError(error))
|
|
61288
|
+
return error;
|
|
61289
|
+
if (!(error instanceof Error))
|
|
61290
|
+
return;
|
|
61291
|
+
const code = workflowInfrastructureFault(error.message);
|
|
61292
|
+
return code === undefined ? undefined : new WorkflowInfrastructureError(code, error.message, { cause: error });
|
|
61293
|
+
}
|
|
61294
|
+
var WORKFLOW_INFRASTRUCTURE_ERROR_NAME = "WorkflowInfrastructureError", MAX_CAUSE_DEPTH = 8, FAULT_PATTERNS, WorkflowInfrastructureError;
|
|
61295
|
+
var init_workflow_infrastructure_error = __esm(() => {
|
|
61296
|
+
FAULT_PATTERNS = [
|
|
61297
|
+
[/Local worker (?:process )?cleanup (?:was not confirmed|unconfirmed)/, "worker_cleanup_unconfirmed"],
|
|
61298
|
+
[/Local worker retry limit/, "worker_retry_limit"],
|
|
61299
|
+
[/Local worker (?:startup timed out|exited before readiness)/, "worker_startup_failed"],
|
|
61300
|
+
[/Worker exited before delivery acknowledgement/, "worker_lost"],
|
|
61301
|
+
[/Stale work lease/, "stale_work_lease"],
|
|
61302
|
+
[/Intercom runtime no longer active/, "intercom_unavailable"],
|
|
61303
|
+
[/Storage unavailable/, "storage_unavailable"]
|
|
61304
|
+
];
|
|
61305
|
+
WorkflowInfrastructureError = class WorkflowInfrastructureError extends Error {
|
|
61306
|
+
name = WORKFLOW_INFRASTRUCTURE_ERROR_NAME;
|
|
61307
|
+
retryable = true;
|
|
61308
|
+
code;
|
|
61309
|
+
constructor(code, message, options) {
|
|
61310
|
+
super(message, options);
|
|
61311
|
+
this.code = code;
|
|
61312
|
+
}
|
|
61313
|
+
};
|
|
61314
|
+
});
|
|
61315
|
+
|
|
61160
61316
|
// dist/builtin/workflows/src/workers/host-options.ts
|
|
61161
61317
|
var hostWorkerBindings;
|
|
61162
61318
|
var init_host_options = __esm(() => {
|
|
61163
61319
|
hostWorkerBindings = Symbol("host-worker-bindings");
|
|
61164
61320
|
});
|
|
61165
61321
|
|
|
61322
|
+
// dist/builtin/workflows/src/workers/protocol.ts
|
|
61323
|
+
var WORKER_HEARTBEAT_INTERVAL_MS = 1000;
|
|
61324
|
+
|
|
61166
61325
|
// dist/builtin/workflows/src/runs/foreground/pending-stage-delivery.ts
|
|
61167
61326
|
function isWorkflowPendingStageDeliveryFailure(error) {
|
|
61168
61327
|
if (error instanceof WorkflowPendingStageDeliveryFailedError)
|
|
@@ -61702,20 +61861,33 @@ var init_stage_handoff = __esm(() => {
|
|
|
61702
61861
|
// dist/builtin/workflows/src/workers/local-pool.ts
|
|
61703
61862
|
import { fork } from "node:child_process";
|
|
61704
61863
|
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
61705
|
-
import {
|
|
61864
|
+
import { createWriteStream } from "node:fs";
|
|
61865
|
+
import { mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
61866
|
+
import { dirname as dirname12, join as join28, resolve as resolve11 } from "node:path";
|
|
61706
61867
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
61707
61868
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
61708
61869
|
import { isBunBinary as isBunBinary2 } from "@bastani/atomic";
|
|
61870
|
+
function workerLogDirectory(journalPath, root) {
|
|
61871
|
+
return join28(dirname12(resolve11(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
|
|
61872
|
+
}
|
|
61709
61873
|
|
|
61710
61874
|
class LocalWorkerPool {
|
|
61711
61875
|
backend;
|
|
61712
61876
|
options;
|
|
61713
61877
|
children = new Set;
|
|
61714
61878
|
incarnations = new Map;
|
|
61879
|
+
readyWorkers = new Set;
|
|
61880
|
+
logs = new Map;
|
|
61881
|
+
logDirectory;
|
|
61715
61882
|
cleanups = new Set;
|
|
61716
61883
|
recovering;
|
|
61717
61884
|
nextRecoveryAt = 0;
|
|
61718
61885
|
controlAcks = new Map;
|
|
61886
|
+
lastHeard = new Map;
|
|
61887
|
+
lastTick = performance.now();
|
|
61888
|
+
rootStalledMs = 0;
|
|
61889
|
+
ticker;
|
|
61890
|
+
leaseMs;
|
|
61719
61891
|
desiredControl;
|
|
61720
61892
|
root;
|
|
61721
61893
|
store;
|
|
@@ -61739,9 +61911,15 @@ class LocalWorkerPool {
|
|
|
61739
61911
|
this.options = options;
|
|
61740
61912
|
if (!Number.isSafeInteger(options.workers) || options.workers < 1)
|
|
61741
61913
|
throw new Error("Invalid local worker count");
|
|
61914
|
+
if (options.startupTimeoutMs !== undefined && (!Number.isSafeInteger(options.startupTimeoutMs) || options.startupTimeoutMs < 1 || options.startupTimeoutMs > MAX_TIMER_DELAY_MS))
|
|
61915
|
+
throw new Error("Invalid local worker startup timeout");
|
|
61916
|
+
if (options.leaseMs !== undefined && (!Number.isSafeInteger(options.leaseMs) || options.leaseMs < MINIMUM_WORK_LEASE_MS || options.leaseMs > MAX_TIMER_DELAY_MS))
|
|
61917
|
+
throw new Error(`Invalid local worker lease: must be an integer from ${MINIMUM_WORK_LEASE_MS} to ${MAX_TIMER_DELAY_MS} ms`);
|
|
61918
|
+
this.leaseMs = options.leaseMs ?? DEFAULT_WORK_LEASE_MS;
|
|
61742
61919
|
this.releaseBinding = bindChildWorkerDispatcher(backend, this, options.rootId);
|
|
61743
61920
|
if (options.admission && options.rootId === undefined)
|
|
61744
61921
|
workflowResourceAdmission.set(backend, options.admission);
|
|
61922
|
+
this.ticker = setInterval(() => this.observeResponsiveness(), ROOT_TICK_INTERVAL_MS).unref();
|
|
61745
61923
|
}
|
|
61746
61924
|
get workerPids() {
|
|
61747
61925
|
return [...this.children].flatMap((child) => child.pid === undefined ? [] : [child.pid]);
|
|
@@ -61767,6 +61945,7 @@ class LocalWorkerPool {
|
|
|
61767
61945
|
this.lease = { runId: root, holderId: state.holderId, epoch: state.epoch };
|
|
61768
61946
|
const queue = await openSqlPoolQueue(this.backend.journal);
|
|
61769
61947
|
await queue.initialize(this.lease, COORDINATOR_LEASE_MS);
|
|
61948
|
+
await queue.releasePreviousIncarnations(this.lease);
|
|
61770
61949
|
for (;; ) {
|
|
61771
61950
|
const intended = this.desiredControl ?? "running";
|
|
61772
61951
|
await queue.setControl(this.lease, intended);
|
|
@@ -61781,8 +61960,8 @@ class LocalWorkerPool {
|
|
|
61781
61960
|
if (!this.queue || !this.lease)
|
|
61782
61961
|
return;
|
|
61783
61962
|
const control = await this.queue.setControl(this.lease, state);
|
|
61784
|
-
const deadline = Date.now() +
|
|
61785
|
-
while ([...this.
|
|
61963
|
+
const deadline = Date.now() + CONTROL_ACKNOWLEDGEMENT_TIMEOUT_MS;
|
|
61964
|
+
while ([...this.readyWorkers].some((worker) => (this.controlAcks.get(worker) ?? -1) < control.revision)) {
|
|
61786
61965
|
if (this.desiredControl !== state)
|
|
61787
61966
|
return;
|
|
61788
61967
|
if (Date.now() >= deadline) {
|
|
@@ -61852,7 +62031,16 @@ class LocalWorkerPool {
|
|
|
61852
62031
|
root,
|
|
61853
62032
|
holder: "coordinator"
|
|
61854
62033
|
});
|
|
61855
|
-
|
|
62034
|
+
this.logDirectory = workerLogDirectory(this.options.journalPath, root);
|
|
62035
|
+
await mkdir6(this.logDirectory, { recursive: true }).catch(() => {
|
|
62036
|
+
return;
|
|
62037
|
+
});
|
|
62038
|
+
const workers = Array.from({ length: this.options.workers }, () => this.spawn(root));
|
|
62039
|
+
try {
|
|
62040
|
+
await Promise.any(workers);
|
|
62041
|
+
} catch (error) {
|
|
62042
|
+
throw error.errors[0];
|
|
62043
|
+
}
|
|
61856
62044
|
}
|
|
61857
62045
|
spawn(root) {
|
|
61858
62046
|
if (this.closed)
|
|
@@ -61873,26 +62061,56 @@ class LocalWorkerPool {
|
|
|
61873
62061
|
let serial = Promise.resolve();
|
|
61874
62062
|
let work;
|
|
61875
62063
|
const deliveries = new Map;
|
|
62064
|
+
const logPath = join28(this.logDirectory, `${worker}.log`);
|
|
62065
|
+
this.logs.set(child, logPath);
|
|
62066
|
+
let logFailure;
|
|
62067
|
+
const log = createWriteStream(logPath, { flags: "a" });
|
|
62068
|
+
log.on("error", (error) => {
|
|
62069
|
+
logFailure = error.message;
|
|
62070
|
+
});
|
|
61876
62071
|
let stderr = "";
|
|
61877
62072
|
child.stderr?.on("data", (chunk) => {
|
|
61878
|
-
stderr = (stderr + chunk.toString()).slice(-
|
|
62073
|
+
stderr = (stderr + chunk.toString()).slice(-STDERR_TAIL_CHARACTERS);
|
|
61879
62074
|
});
|
|
62075
|
+
child.stderr?.on("error", (error) => {
|
|
62076
|
+
logFailure ??= error.message;
|
|
62077
|
+
log.end();
|
|
62078
|
+
});
|
|
62079
|
+
child.stderr?.pipe(log);
|
|
62080
|
+
const diagnosed = (summary) => new Error(`${summary} (worker stderr log: ${logFailure === undefined ? logPath : `unavailable, ${logFailure}`})${stderr ? `: ${stderr}` : ""}`);
|
|
62081
|
+
const startupTimeoutMs = this.options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
62082
|
+
let timedOut = false;
|
|
62083
|
+
let terminated = false;
|
|
62084
|
+
const terminate = () => {
|
|
62085
|
+
if (terminated)
|
|
62086
|
+
return;
|
|
62087
|
+
terminated = true;
|
|
62088
|
+
child.kill("SIGKILL");
|
|
62089
|
+
};
|
|
62090
|
+
const replied = (error) => {
|
|
62091
|
+
if (error)
|
|
62092
|
+
terminate();
|
|
62093
|
+
};
|
|
61880
62094
|
return new Promise((resolve, reject) => {
|
|
61881
62095
|
const startup = setTimeout(() => {
|
|
61882
|
-
|
|
61883
|
-
|
|
61884
|
-
|
|
61885
|
-
|
|
61886
|
-
child.once("error", (error) => {
|
|
62096
|
+
timedOut = true;
|
|
62097
|
+
terminate();
|
|
62098
|
+
}, startupTimeoutMs);
|
|
62099
|
+
child.on("error", (error) => {
|
|
61887
62100
|
clearTimeout(startup);
|
|
61888
62101
|
reject(error);
|
|
62102
|
+
terminate();
|
|
61889
62103
|
});
|
|
62104
|
+
const closed = new Promise((resolve) => child.once("close", () => resolve()));
|
|
61890
62105
|
child.once("exit", () => {
|
|
62106
|
+
Promise.race([closed, delay2(STDERR_DRAIN_GRACE_MS)]).then(() => reject(diagnosed(timedOut ? `Local worker startup timed out after ${startupTimeoutMs} ms` : "Local worker exited before readiness")));
|
|
61891
62107
|
this.children.delete(child);
|
|
62108
|
+
this.logs.delete(child);
|
|
61892
62109
|
clearTimeout(startup);
|
|
61893
62110
|
this.incarnations.delete(worker);
|
|
61894
|
-
|
|
62111
|
+
this.readyWorkers.delete(worker);
|
|
61895
62112
|
this.controlAcks.delete(worker);
|
|
62113
|
+
this.lastHeard.delete(worker);
|
|
61896
62114
|
if (work)
|
|
61897
62115
|
this.handoff?.fence(work);
|
|
61898
62116
|
for (const delivery of deliveries.values())
|
|
@@ -61915,9 +62133,11 @@ class LocalWorkerPool {
|
|
|
61915
62133
|
}
|
|
61916
62134
|
if (this.closed)
|
|
61917
62135
|
return;
|
|
62136
|
+
if (work)
|
|
62137
|
+
await this.queue.releaseExited(this.lease, work);
|
|
61918
62138
|
const exhausted = work ? work.generation >= 3 : ++this.replacements > 3;
|
|
61919
62139
|
if (exhausted)
|
|
61920
|
-
this.failure =
|
|
62140
|
+
this.failure = diagnosed("Local worker retry limit");
|
|
61921
62141
|
else
|
|
61922
62142
|
await this.spawn(root);
|
|
61923
62143
|
}).catch((error) => {
|
|
@@ -61927,6 +62147,8 @@ class LocalWorkerPool {
|
|
|
61927
62147
|
cleanup.finally(() => this.cleanups.delete(cleanup));
|
|
61928
62148
|
});
|
|
61929
62149
|
child.on("message", (message) => {
|
|
62150
|
+
this.observeResponsiveness();
|
|
62151
|
+
this.lastHeard.set(worker, { at: performance.now(), rootStalled: this.rootStalledMs });
|
|
61930
62152
|
if (message.kind === "delivery-ack") {
|
|
61931
62153
|
const pending = deliveries.get(message.deliveryId);
|
|
61932
62154
|
deliveries.delete(message.deliveryId);
|
|
@@ -61938,7 +62160,10 @@ class LocalWorkerPool {
|
|
|
61938
62160
|
}
|
|
61939
62161
|
const response = serial.then(async () => {
|
|
61940
62162
|
if (message.kind === "ready") {
|
|
62163
|
+
if (terminated)
|
|
62164
|
+
return;
|
|
61941
62165
|
ready = true;
|
|
62166
|
+
this.readyWorkers.add(worker);
|
|
61942
62167
|
clearTimeout(startup);
|
|
61943
62168
|
resolve();
|
|
61944
62169
|
return;
|
|
@@ -61965,11 +62190,13 @@ class LocalWorkerPool {
|
|
|
61965
62190
|
work = await queue.claim(lease, worker, this.sources.map((source) => ({
|
|
61966
62191
|
definition: `${source.path}#${source.exportName}`,
|
|
61967
62192
|
digest: source.digest
|
|
61968
|
-
})),
|
|
62193
|
+
})), this.leaseMs);
|
|
61969
62194
|
return work;
|
|
61970
62195
|
}
|
|
61971
62196
|
if (!work)
|
|
61972
62197
|
throw new Error("Worker has no active attempt");
|
|
62198
|
+
if (message.kind === "renew" || work.expiresAt - Date.now() < this.leaseMs / 2)
|
|
62199
|
+
work = await queue.extend(lease, work, this.leaseMs);
|
|
61973
62200
|
if (message.kind === "activity")
|
|
61974
62201
|
return this.handoff?.publish(work, message.runs);
|
|
61975
62202
|
if (message.kind === "route")
|
|
@@ -61990,10 +62217,8 @@ class LocalWorkerPool {
|
|
|
61990
62217
|
});
|
|
61991
62218
|
}));
|
|
61992
62219
|
}
|
|
61993
|
-
if (message.kind === "renew")
|
|
61994
|
-
work = await queue.renew(lease, work, randomUUID15(), WORK_LEASE_MS);
|
|
62220
|
+
if (message.kind === "renew")
|
|
61995
62221
|
return;
|
|
61996
|
-
}
|
|
61997
62222
|
if (message.kind === "commit") {
|
|
61998
62223
|
const receipt = await queue.commit(lease, work, message.operation, message.mutation);
|
|
61999
62224
|
this.usageTotal = await this.usageLedger.total(root);
|
|
@@ -62018,13 +62243,7 @@ class LocalWorkerPool {
|
|
|
62018
62243
|
});
|
|
62019
62244
|
if (message.kind !== "delivery" && message.kind !== "delivery-ready")
|
|
62020
62245
|
serial = response.then(() => {}, () => {});
|
|
62021
|
-
response.then((value2) => {
|
|
62022
|
-
if (child.connected)
|
|
62023
|
-
child.send({ id: message.id, value: value2 });
|
|
62024
|
-
}, (error) => {
|
|
62025
|
-
if (child.connected)
|
|
62026
|
-
child.send({ id: message.id, error: error.message });
|
|
62027
|
-
});
|
|
62246
|
+
response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => child.send({ id: message.id, error: error.message }, replied));
|
|
62028
62247
|
});
|
|
62029
62248
|
});
|
|
62030
62249
|
}
|
|
@@ -62034,14 +62253,22 @@ class LocalWorkerPool {
|
|
|
62034
62253
|
if (this.closed || performance.now() < this.nextRecoveryAt)
|
|
62035
62254
|
return Promise.resolve();
|
|
62036
62255
|
this.recovering = (async () => {
|
|
62256
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
62037
62257
|
await this.admission?.reconcile();
|
|
62038
62258
|
const expiredBefore = Date.now();
|
|
62039
62259
|
for (const work of await this.queue.inspect(root)) {
|
|
62040
62260
|
if (work.state !== "leased" || work.expiresAt >= expiredBefore)
|
|
62041
62261
|
continue;
|
|
62042
62262
|
const child = work.worker === null ? undefined : this.incarnations.get(work.worker);
|
|
62043
|
-
if (child)
|
|
62044
|
-
await this.
|
|
62263
|
+
if (child && work.worker !== null && this.isLive(work.worker, child)) {
|
|
62264
|
+
await this.queue.extend(this.lease, work, this.leaseMs).catch((error) => {
|
|
62265
|
+
if (error.message !== STALE_WORK_LEASE)
|
|
62266
|
+
throw error;
|
|
62267
|
+
});
|
|
62268
|
+
continue;
|
|
62269
|
+
}
|
|
62270
|
+
if (child && !await this.stop(child).then(() => true, () => false))
|
|
62271
|
+
continue;
|
|
62045
62272
|
await this.queue.expire(this.lease, work);
|
|
62046
62273
|
}
|
|
62047
62274
|
})().finally(() => {
|
|
@@ -62050,6 +62277,18 @@ class LocalWorkerPool {
|
|
|
62050
62277
|
});
|
|
62051
62278
|
return this.recovering;
|
|
62052
62279
|
}
|
|
62280
|
+
observeResponsiveness() {
|
|
62281
|
+
const now = performance.now();
|
|
62282
|
+
const gap = now - this.lastTick;
|
|
62283
|
+
if (gap > ROOT_STALL_THRESHOLD_MS)
|
|
62284
|
+
this.rootStalledMs += gap - ROOT_TICK_INTERVAL_MS;
|
|
62285
|
+
this.lastTick = now;
|
|
62286
|
+
}
|
|
62287
|
+
isLive(worker, child) {
|
|
62288
|
+
this.observeResponsiveness();
|
|
62289
|
+
const heard = this.lastHeard.get(worker);
|
|
62290
|
+
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.rootStalledMs - heard.rootStalled) < this.leaseMs;
|
|
62291
|
+
}
|
|
62053
62292
|
stop(child) {
|
|
62054
62293
|
if (child.pid === undefined || child.exitCode !== null || child.signalCode !== null)
|
|
62055
62294
|
return Promise.resolve();
|
|
@@ -62066,9 +62305,13 @@ class LocalWorkerPool {
|
|
|
62066
62305
|
try {
|
|
62067
62306
|
return await this.dispatch(definition, inputs, options);
|
|
62068
62307
|
} catch (error) {
|
|
62069
|
-
|
|
62070
|
-
|
|
62071
|
-
|
|
62308
|
+
try {
|
|
62309
|
+
if (this.desiredControl !== "quit" || !findWorkflowGracefulQuit(error))
|
|
62310
|
+
await this.close();
|
|
62311
|
+
} catch (closeError) {
|
|
62312
|
+
throw asWorkflowInfrastructureError(closeError) ?? closeError;
|
|
62313
|
+
}
|
|
62314
|
+
throw asWorkflowInfrastructureError(error) ?? error;
|
|
62072
62315
|
}
|
|
62073
62316
|
}
|
|
62074
62317
|
async dispatch(definition, inputs, options) {
|
|
@@ -62112,6 +62355,8 @@ class LocalWorkerPool {
|
|
|
62112
62355
|
for (;; ) {
|
|
62113
62356
|
options.signal?.throwIfAborted();
|
|
62114
62357
|
if (this.closed) {
|
|
62358
|
+
if (this.failure)
|
|
62359
|
+
throw this.failure;
|
|
62115
62360
|
if (this.desiredControl === "quit")
|
|
62116
62361
|
throw new WorkflowGracefulQuitError(root, "worker pool teardown");
|
|
62117
62362
|
throw new Error("Local worker pool is closed");
|
|
@@ -62138,19 +62383,28 @@ class LocalWorkerPool {
|
|
|
62138
62383
|
}
|
|
62139
62384
|
async dispose() {
|
|
62140
62385
|
this.closed = true;
|
|
62386
|
+
clearInterval(this.ticker);
|
|
62141
62387
|
this.releaseBinding();
|
|
62142
62388
|
if (this.options.rootId === undefined)
|
|
62143
62389
|
workflowResourceAdmission.delete(this.backend);
|
|
62144
62390
|
let failure;
|
|
62391
|
+
let stopping = [];
|
|
62145
62392
|
try {
|
|
62146
62393
|
await this.recovering?.catch(() => {});
|
|
62147
|
-
|
|
62394
|
+
stopping = [...this.children].map((child) => ({ child, log: this.logs.get(child) }));
|
|
62395
|
+
await Promise.all(stopping.map(({ child }) => this.stop(child)));
|
|
62148
62396
|
await Promise.all([...this.cleanups]);
|
|
62149
62397
|
if (this.cleanupFailure)
|
|
62150
62398
|
throw this.cleanupFailure;
|
|
62151
62399
|
} catch (error) {
|
|
62152
62400
|
failure = error;
|
|
62153
62401
|
}
|
|
62402
|
+
if (failure === undefined) {
|
|
62403
|
+
const stopped = stopping.flatMap(({ child, log }) => log !== undefined && (child.exitCode !== null || child.signalCode !== null) ? [log] : []);
|
|
62404
|
+
await Promise.all(stopped.map((log) => rm3(log, { force: true }).catch(() => {})));
|
|
62405
|
+
if (this.logDirectory !== undefined)
|
|
62406
|
+
await rmdir(this.logDirectory).catch(() => {});
|
|
62407
|
+
}
|
|
62154
62408
|
try {
|
|
62155
62409
|
await this.releaseRoutes?.();
|
|
62156
62410
|
} catch (error) {
|
|
@@ -62160,7 +62414,7 @@ class LocalWorkerPool {
|
|
|
62160
62414
|
throw failure;
|
|
62161
62415
|
}
|
|
62162
62416
|
}
|
|
62163
|
-
var INTERNAL_WORKFLOW_WORKER_ARG = "--internal-workflow-worker",
|
|
62417
|
+
var INTERNAL_WORKFLOW_WORKER_ARG = "--internal-workflow-worker", DEFAULT_WORK_LEASE_MS = 30000, MINIMUM_WORK_LEASE_MS, CONTROL_ACKNOWLEDGEMENT_TIMEOUT_MS = 5000, RECOVERY_INTERVAL_MS = 500, ROOT_TICK_INTERVAL_MS = 100, ROOT_STALL_THRESHOLD_MS = 500, COORDINATOR_LEASE_MS, DEFAULT_STARTUP_TIMEOUT_MS = 30000, MAX_TIMER_DELAY_MS = 2147483647, STDERR_TAIL_CHARACTERS = 8192, STDERR_DRAIN_GRACE_MS = 1000;
|
|
62164
62418
|
var init_local_pool = __esm(() => {
|
|
62165
62419
|
init_internal();
|
|
62166
62420
|
init_sql_pool_queue();
|
|
@@ -62168,12 +62422,14 @@ var init_local_pool = __esm(() => {
|
|
|
62168
62422
|
init_sql_run_journal();
|
|
62169
62423
|
init_workflow_tool_abort();
|
|
62170
62424
|
init_sdk_intercom();
|
|
62425
|
+
init_workflow_infrastructure_error();
|
|
62171
62426
|
init_admission_binding();
|
|
62172
62427
|
init_definitions();
|
|
62173
62428
|
init_dispatch();
|
|
62174
62429
|
init_host_options();
|
|
62175
62430
|
init_resource_admission();
|
|
62176
62431
|
init_stage_handoff();
|
|
62432
|
+
MINIMUM_WORK_LEASE_MS = 2 * WORKER_HEARTBEAT_INTERVAL_MS;
|
|
62177
62433
|
COORDINATOR_LEASE_MS = 3 * STAGE_SESSION_HEARTBEAT_INTERVAL_MS;
|
|
62178
62434
|
});
|
|
62179
62435
|
|
|
@@ -62215,6 +62471,8 @@ async function activatePublicPool(backend, options) {
|
|
|
62215
62471
|
const cwd = options.cwd ?? process.cwd();
|
|
62216
62472
|
const localWorkers = options.localWorkers && {
|
|
62217
62473
|
...options.localWorkers,
|
|
62474
|
+
startupTimeoutMs: undefined,
|
|
62475
|
+
leaseMs: undefined,
|
|
62218
62476
|
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve12(cwd, source.path) }))
|
|
62219
62477
|
};
|
|
62220
62478
|
const admission = options.admission && {
|
|
@@ -62243,7 +62501,9 @@ async function activatePublicPool(backend, options) {
|
|
|
62243
62501
|
journalPath: backend.journal.path,
|
|
62244
62502
|
workers: localWorkers.count,
|
|
62245
62503
|
definitions,
|
|
62246
|
-
admission: resources.admission ?? {}
|
|
62504
|
+
admission: resources.admission ?? {},
|
|
62505
|
+
startupTimeoutMs: options.localWorkers?.startupTimeoutMs,
|
|
62506
|
+
leaseMs: options.localWorkers?.leaseMs
|
|
62247
62507
|
});
|
|
62248
62508
|
try {
|
|
62249
62509
|
pool.validateOptions(options);
|
|
@@ -63161,12 +63421,12 @@ function createChildWorkflowRunner(input) {
|
|
|
63161
63421
|
const childExitStatus = isWorkflowExitStatus(childRun.status) ? childRun.status : "blocked";
|
|
63162
63422
|
if (!isWorkflowExitStatus(childRun.status) && !childBudgetExceeded || childRun.status === "failed" && childRun.exited !== true) {
|
|
63163
63423
|
const failedChildStage = childRun.stages.find((stage) => stage.failureKind !== undefined);
|
|
63164
|
-
|
|
63165
|
-
|
|
63166
|
-
|
|
63167
|
-
|
|
63168
|
-
|
|
63169
|
-
});
|
|
63424
|
+
const message = `atomic-workflows: child workflow "${childName}" (${child.name}) failed with status ${childRun.status}${childRun.error !== undefined ? `: ${childRun.error}` : ""}`;
|
|
63425
|
+
const cause = {
|
|
63426
|
+
...failedChildStage?.failureKind !== undefined ? { code: failedChildStage.failureKind } : {},
|
|
63427
|
+
...failedChildStage?.failureMessage !== undefined ? { message: failedChildStage.failureMessage } : {}
|
|
63428
|
+
};
|
|
63429
|
+
throw new Error(message, { cause });
|
|
63170
63430
|
}
|
|
63171
63431
|
const outputs = selectWorkflowOutputs(child, childRun.result);
|
|
63172
63432
|
const childExited = childBudgetExceeded || childRun.exited === true || childRun.status !== "completed";
|
|
@@ -63227,7 +63487,7 @@ function describeErrorWithCauses(error) {
|
|
|
63227
63487
|
const messages = [];
|
|
63228
63488
|
const visited = new Set;
|
|
63229
63489
|
let current = error;
|
|
63230
|
-
for (let depth = 0;current !== undefined && depth <
|
|
63490
|
+
for (let depth = 0;current !== undefined && depth < MAX_CAUSE_DEPTH2 && !visited.has(current); depth++) {
|
|
63231
63491
|
visited.add(current);
|
|
63232
63492
|
const message = current instanceof Error ? current.message : String(current);
|
|
63233
63493
|
if (!messages.includes(message))
|
|
@@ -63236,7 +63496,7 @@ function describeErrorWithCauses(error) {
|
|
|
63236
63496
|
}
|
|
63237
63497
|
return messages.join(": ");
|
|
63238
63498
|
}
|
|
63239
|
-
var
|
|
63499
|
+
var MAX_CAUSE_DEPTH2 = 5;
|
|
63240
63500
|
|
|
63241
63501
|
// dist/builtin/workflows/src/shared/returned-run-status.ts
|
|
63242
63502
|
function normalizeReturnedWorkflowStatus(status) {
|
|
@@ -63563,7 +63823,7 @@ function hasUsableContentBlock(block) {
|
|
|
63563
63823
|
|
|
63564
63824
|
// dist/builtin/workflows/src/shared/stage-session-store.ts
|
|
63565
63825
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
63566
|
-
import { dirname as
|
|
63826
|
+
import { dirname as dirname13, resolve as resolve13 } from "node:path";
|
|
63567
63827
|
import {
|
|
63568
63828
|
JsonlSessionStore,
|
|
63569
63829
|
resolveSessionStore,
|
|
@@ -63600,7 +63860,7 @@ async function migrateLegacyStageSession(store, sessionId, sessionFile) {
|
|
|
63600
63860
|
if (sessionFile === undefined || await store.readHeader(sessionId) !== undefined)
|
|
63601
63861
|
return;
|
|
63602
63862
|
const location = resolve13(sessionFile);
|
|
63603
|
-
const legacy = await JsonlSessionStore.open(
|
|
63863
|
+
const legacy = await JsonlSessionStore.open(dirname13(location), { exactDirectory: true, scanExisting: false });
|
|
63604
63864
|
try {
|
|
63605
63865
|
for await (const file of legacy.scanFiles()) {
|
|
63606
63866
|
if (resolve13(file.location) !== location || file.header.id !== sessionId)
|
|
@@ -64748,7 +65008,7 @@ function recordedOwners(boundary, reason) {
|
|
|
64748
65008
|
const pending = [{ value: reason, depth: 0 }];
|
|
64749
65009
|
while (pending.length > 0) {
|
|
64750
65010
|
const { value: value2, depth } = pending.pop();
|
|
64751
|
-
if (depth >
|
|
65011
|
+
if (depth > MAX_CAUSE_DEPTH3)
|
|
64752
65012
|
continue;
|
|
64753
65013
|
if (isPrimitive(value2)) {
|
|
64754
65014
|
if (depth === 0 || value2 !== undefined && value2 !== null) {
|
|
@@ -65070,7 +65330,7 @@ function containUiRejections(ui, scope) {
|
|
|
65070
65330
|
custom: (factory, options) => scope.watch(ui.custom(factory, options))
|
|
65071
65331
|
};
|
|
65072
65332
|
}
|
|
65073
|
-
var EVENT = "unhandledRejection", BOUNDARY_KEY, FLAG = "--unhandled-rejections",
|
|
65333
|
+
var EVENT = "unhandledRejection", BOUNDARY_KEY, FLAG = "--unhandled-rejections", MAX_CAUSE_DEPTH3 = 8, MAX_PRIMITIVES_PER_RUN = 64, MAX_STOP_STRINGS = 64, ENDED_RUN_GRACE_MS = 30000, NATIVE_REPORTING_MODES, WATCHED_STAGE_METHODS;
|
|
65074
65334
|
var init_run_rejection_boundary = __esm(() => {
|
|
65075
65335
|
init_prompt_callsite();
|
|
65076
65336
|
init_workflow_source();
|
|
@@ -69863,8 +70123,8 @@ var init_stage_runner_controller = __esm(() => {
|
|
|
69863
70123
|
|
|
69864
70124
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
|
|
69865
70125
|
import { createHash as createHash4 } from "node:crypto";
|
|
69866
|
-
import { mkdir as
|
|
69867
|
-
import { basename as basename5, dirname as
|
|
70126
|
+
import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
|
|
70127
|
+
import { basename as basename5, dirname as dirname14, isAbsolute as isAbsolute11, join as join29, resolve as resolve14 } from "node:path";
|
|
69868
70128
|
function normalizeMaxOutput2(maxOutput) {
|
|
69869
70129
|
return {
|
|
69870
70130
|
bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
@@ -69927,7 +70187,7 @@ function formatByteSize(bytes) {
|
|
|
69927
70187
|
}
|
|
69928
70188
|
function transcriptPath(runId, outputPath) {
|
|
69929
70189
|
const digest = createHash4("sha256").update(outputPath).digest("hex").slice(0, 16);
|
|
69930
|
-
return
|
|
70190
|
+
return join29(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
|
|
69931
70191
|
}
|
|
69932
70192
|
function appendContent(lines, content) {
|
|
69933
70193
|
if (typeof content === "string") {
|
|
@@ -70047,7 +70307,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
|
|
|
70047
70307
|
const transcriptFile = transcriptPath(runId, outputPath);
|
|
70048
70308
|
const transcript = renderTranscript(messages, fullOutput);
|
|
70049
70309
|
try {
|
|
70050
|
-
await
|
|
70310
|
+
await mkdir7(dirname14(outputPath), { recursive: true });
|
|
70051
70311
|
await writeFile10(outputPath, fullOutput, "utf8");
|
|
70052
70312
|
} catch (err) {
|
|
70053
70313
|
return `${displayOutput}
|
|
@@ -70059,7 +70319,7 @@ ${err instanceof Error ? err.message : String(err)}`;
|
|
|
70059
70319
|
let transcriptError;
|
|
70060
70320
|
try {
|
|
70061
70321
|
await ensureWorkflowArtifactRunDirectory(runId);
|
|
70062
|
-
await
|
|
70322
|
+
await mkdir7(dirname14(transcriptFile), { recursive: true });
|
|
70063
70323
|
await writeFile10(transcriptFile, transcript, "utf8");
|
|
70064
70324
|
transcriptAvailable = true;
|
|
70065
70325
|
} catch (err) {
|
|
@@ -70968,7 +71228,7 @@ function reportsClosedSession(error) {
|
|
|
70968
71228
|
}
|
|
70969
71229
|
function isSessionClosedError(error) {
|
|
70970
71230
|
let current = error;
|
|
70971
|
-
for (let depth = 0;depth <
|
|
71231
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH4 && current !== undefined; depth++) {
|
|
70972
71232
|
try {
|
|
70973
71233
|
if (reportsClosedSession(current))
|
|
70974
71234
|
return true;
|
|
@@ -70979,7 +71239,7 @@ function isSessionClosedError(error) {
|
|
|
70979
71239
|
}
|
|
70980
71240
|
return false;
|
|
70981
71241
|
}
|
|
70982
|
-
var
|
|
71242
|
+
var MAX_CAUSE_DEPTH4 = 8;
|
|
70983
71243
|
var init_session_closed_error = () => {};
|
|
70984
71244
|
|
|
70985
71245
|
// dist/builtin/workflows/src/engine/workflow-activity.ts
|
|
@@ -72220,11 +72480,13 @@ __export(exports_sdk_surface, {
|
|
|
72220
72480
|
StaleLeaseError: () => StaleLeaseError,
|
|
72221
72481
|
StorageUnavailableError: () => StorageUnavailableError,
|
|
72222
72482
|
WORKFLOW_HEARTBEAT_CUSTOM_TYPE: () => WORKFLOW_HEARTBEAT_CUSTOM_TYPE,
|
|
72483
|
+
WorkflowInfrastructureError: () => WorkflowInfrastructureError,
|
|
72223
72484
|
cancellationRegistry: () => cancellationRegistry,
|
|
72224
72485
|
createAgentSessionAdapter: () => createAgentSessionAdapter,
|
|
72225
72486
|
createCancellationRegistry: () => createCancellationRegistry,
|
|
72226
72487
|
createRegistry: () => createRegistry,
|
|
72227
72488
|
createStore: () => createStore,
|
|
72489
|
+
isRetryableWorkflowError: () => isRetryableWorkflowError,
|
|
72228
72490
|
keepContext: () => keepContext,
|
|
72229
72491
|
loadWorkerWorkflow: () => loadWorkerWorkflow,
|
|
72230
72492
|
normalizeWorkflowName: () => normalizeWorkflowName,
|
|
@@ -72251,6 +72513,7 @@ var init_sdk_surface = __esm(() => {
|
|
|
72251
72513
|
init_worktree();
|
|
72252
72514
|
init_store();
|
|
72253
72515
|
init_types2();
|
|
72516
|
+
init_workflow_infrastructure_error();
|
|
72254
72517
|
init_definitions();
|
|
72255
72518
|
init_registry();
|
|
72256
72519
|
init_types();
|
|
@@ -72284,11 +72547,13 @@ export {
|
|
|
72284
72547
|
StaleLeaseError,
|
|
72285
72548
|
StorageUnavailableError,
|
|
72286
72549
|
WORKFLOW_HEARTBEAT_CUSTOM_TYPE,
|
|
72550
|
+
WorkflowInfrastructureError,
|
|
72287
72551
|
cancellationRegistry,
|
|
72288
72552
|
createAgentSessionAdapter,
|
|
72289
72553
|
createCancellationRegistry,
|
|
72290
72554
|
createRegistry,
|
|
72291
72555
|
createStore,
|
|
72556
|
+
isRetryableWorkflowError,
|
|
72292
72557
|
keepContext,
|
|
72293
72558
|
loadWorkerWorkflow,
|
|
72294
72559
|
normalizeWorkflowName,
|