@bastani/atomic 0.9.42 → 0.9.43-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 +19 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -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 +19 -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
|
@@ -6491,8 +6491,14 @@ function registerSqlPoolStorage(journal, storage) {
|
|
|
6491
6491
|
function sqlPoolStorage(journal) {
|
|
6492
6492
|
return poolStorage.get(journal);
|
|
6493
6493
|
}
|
|
6494
|
-
var JOURNAL_READ_PAGE_SIZE = 256, versionReaders, poolStorage;
|
|
6494
|
+
var JOURNAL_READ_PAGE_SIZE = 256, NON_SNAPSHOT_EVENT_TYPES, versionReaders, poolStorage;
|
|
6495
6495
|
var init_internal = __esm(() => {
|
|
6496
|
+
init_types();
|
|
6497
|
+
NON_SNAPSHOT_EVENT_TYPES = [
|
|
6498
|
+
RUN_EVENT_TYPES.checkpointRecorded,
|
|
6499
|
+
RUN_EVENT_TYPES.messageSettled,
|
|
6500
|
+
RUN_EVENT_TYPES.messageDelivered
|
|
6501
|
+
];
|
|
6496
6502
|
versionReaders = new WeakMap;
|
|
6497
6503
|
poolStorage = new WeakMap;
|
|
6498
6504
|
});
|
|
@@ -6800,6 +6806,7 @@ class JournalDurableBackend {
|
|
|
6800
6806
|
projection = createJournalProjection();
|
|
6801
6807
|
sequences = new Map;
|
|
6802
6808
|
foldedAt = new Map;
|
|
6809
|
+
summarized = new Map;
|
|
6803
6810
|
catalogToken;
|
|
6804
6811
|
leases = new Map;
|
|
6805
6812
|
executions = new Map;
|
|
@@ -6825,8 +6832,8 @@ class JournalDurableBackend {
|
|
|
6825
6832
|
let backend;
|
|
6826
6833
|
try {
|
|
6827
6834
|
backend = new JournalDurableBackend(journal, undefined, options.ownsJournal ?? true);
|
|
6828
|
-
for (const
|
|
6829
|
-
for await (const entry of journal.read(
|
|
6835
|
+
for (const runId of options.runs ?? (await journal.listRuns()).map((run) => run.runId))
|
|
6836
|
+
for await (const entry of journal.read(runId))
|
|
6830
6837
|
backend.fold(entry);
|
|
6831
6838
|
return backend;
|
|
6832
6839
|
} catch (error) {
|
|
@@ -6899,6 +6906,18 @@ class JournalDurableBackend {
|
|
|
6899
6906
|
this.sequences.set(entry.runId, entry.seq);
|
|
6900
6907
|
this.foldedAt.set(entry.runId, entry.at);
|
|
6901
6908
|
}
|
|
6909
|
+
summarize(runId, tail) {
|
|
6910
|
+
const event = tail.snapshot.event;
|
|
6911
|
+
const handle = event.type === RUN_EVENT_TYPES.promptAsked || event.type === RUN_EVENT_TYPES.promptReleased ? event.payload.handle : event.payload;
|
|
6912
|
+
this.projection.deleteWorkflow(runId);
|
|
6913
|
+
this.prompts.delete(runId);
|
|
6914
|
+
this.projection.applyWorkflowSnapshot({
|
|
6915
|
+
...handle,
|
|
6916
|
+
completedCheckpoints: handle.completedCheckpoints + tail.laterCheckpoints,
|
|
6917
|
+
...tail.lastCheckpointAt === undefined ? {} : { updatedAt: tail.lastCheckpointAt }
|
|
6918
|
+
});
|
|
6919
|
+
this.summarized.set(runId, tail.version);
|
|
6920
|
+
}
|
|
6902
6921
|
*entries(runId, fromSeq) {
|
|
6903
6922
|
return yield* invoke(async () => {
|
|
6904
6923
|
const entries = [];
|
|
@@ -6912,6 +6931,7 @@ class JournalDurableBackend {
|
|
|
6912
6931
|
this.projection.deleteWorkflow(runId);
|
|
6913
6932
|
this.sequences.delete(runId);
|
|
6914
6933
|
this.foldedAt.delete(runId);
|
|
6934
|
+
this.summarized.delete(runId);
|
|
6915
6935
|
this.prompts.delete(runId);
|
|
6916
6936
|
for (const entry of entries)
|
|
6917
6937
|
this.fold(entry);
|
|
@@ -7233,6 +7253,9 @@ class JournalDurableBackend {
|
|
|
7233
7253
|
async hydrateWorkflow(runId) {
|
|
7234
7254
|
await this.serialize(runId, () => this.rebuild(runId), false);
|
|
7235
7255
|
}
|
|
7256
|
+
async catchUpWorkflow(runId) {
|
|
7257
|
+
await this.serialize(runId, () => this.extend(runId), false);
|
|
7258
|
+
}
|
|
7236
7259
|
hydrateResumableWorkflows() {
|
|
7237
7260
|
return this.serialize(this.catalogQueue, () => invoke(async () => {
|
|
7238
7261
|
const journal = runJournalVersions(this.journal);
|
|
@@ -7246,16 +7269,33 @@ class JournalDurableBackend {
|
|
|
7246
7269
|
if (token === this.catalogToken)
|
|
7247
7270
|
return;
|
|
7248
7271
|
const versions = await journal.runVersions();
|
|
7249
|
-
for (const runId of new Set([...this.sequences.keys(), ...versions.keys()]))
|
|
7250
|
-
await this.serialize(runId, () => this.catchUp(runId, versions.get(runId)), false);
|
|
7272
|
+
for (const runId of new Set([...this.sequences.keys(), ...this.summarized.keys(), ...versions.keys()]))
|
|
7273
|
+
await this.serialize(runId, () => this.catchUp(runId, versions.get(runId), journal), false);
|
|
7251
7274
|
this.catalogToken = token;
|
|
7252
7275
|
}));
|
|
7253
7276
|
}
|
|
7254
|
-
*catchUp(runId, version) {
|
|
7277
|
+
*catchUp(runId, version, journal) {
|
|
7255
7278
|
const folded = this.sequences.get(runId) ?? 0;
|
|
7279
|
+
if (folded === 0 && version !== undefined) {
|
|
7280
|
+
const summarized = this.summarized.get(runId);
|
|
7281
|
+
if (summarized !== undefined && summarized.seq === version.seq && summarized.at === version.at)
|
|
7282
|
+
return;
|
|
7283
|
+
const tail = yield* invoke(() => journal.snapshotTail(runId));
|
|
7284
|
+
if (tail !== undefined)
|
|
7285
|
+
return this.summarize(runId, tail);
|
|
7286
|
+
if (summarized === undefined && version.seq === 0)
|
|
7287
|
+
return;
|
|
7288
|
+
return yield* this.rebuild(runId);
|
|
7289
|
+
}
|
|
7256
7290
|
if (version !== undefined && version.seq === folded && version.at === (this.foldedAt.get(runId) ?? 0))
|
|
7257
7291
|
return;
|
|
7258
|
-
if (version !== undefined && folded > 0 && version.seq > folded)
|
|
7292
|
+
if (version !== undefined && folded > 0 && version.seq > folded)
|
|
7293
|
+
return yield* this.extend(runId);
|
|
7294
|
+
yield* this.rebuild(runId);
|
|
7295
|
+
}
|
|
7296
|
+
*extend(runId) {
|
|
7297
|
+
const folded = this.sequences.get(runId) ?? 0;
|
|
7298
|
+
if (folded > 0) {
|
|
7259
7299
|
const entries = yield* this.entries(runId, folded);
|
|
7260
7300
|
if (entries[0]?.seq === folded && entries[0].at === this.foldedAt.get(runId)) {
|
|
7261
7301
|
for (const entry of entries)
|
|
@@ -7283,6 +7323,7 @@ class JournalDurableBackend {
|
|
|
7283
7323
|
this.leases.delete(runId);
|
|
7284
7324
|
this.sequences.delete(runId);
|
|
7285
7325
|
this.foldedAt.delete(runId);
|
|
7326
|
+
this.summarized.delete(runId);
|
|
7286
7327
|
this.prompts.delete(runId);
|
|
7287
7328
|
this.projection.deleteWorkflow(runId);
|
|
7288
7329
|
}
|
|
@@ -7647,7 +7688,8 @@ class SqlRunJournal {
|
|
|
7647
7688
|
this.legacy = legacy;
|
|
7648
7689
|
registerRunJournalVersions(this, {
|
|
7649
7690
|
changeToken: () => this.changeToken(),
|
|
7650
|
-
runVersions: () => this.runVersions()
|
|
7691
|
+
runVersions: () => this.runVersions(),
|
|
7692
|
+
snapshotTail: (runId) => this.snapshotTail(runId)
|
|
7651
7693
|
});
|
|
7652
7694
|
registerSqlPoolStorage(this, {
|
|
7653
7695
|
transaction: (body) => this.operation(() => this.database.transaction(body)),
|
|
@@ -7773,6 +7815,28 @@ class SqlRunJournal {
|
|
|
7773
7815
|
]));
|
|
7774
7816
|
});
|
|
7775
7817
|
}
|
|
7818
|
+
async snapshotTail(runId) {
|
|
7819
|
+
this.assertOpen();
|
|
7820
|
+
validateText("runId", runId);
|
|
7821
|
+
return this.operation(async () => {
|
|
7822
|
+
const events = await this.isUnconvertedLegacyRun(runId) ? JOURNAL_TABLES.events : this.tables.events;
|
|
7823
|
+
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} = ?`;
|
|
7824
|
+
const row = await this.database.get(`SELECT ${EVENT_COLUMNS.map((column) => `snapshot.${column}`).join(", ")},
|
|
7825
|
+
latest.${JOURNAL_COLUMNS.seq} AS latest_seq, latest.${JOURNAL_COLUMNS.at} AS latest_at,
|
|
7826
|
+
(SELECT count(*) ${later}) AS later_checkpoints,
|
|
7827
|
+
(SELECT json_extract(later.${JOURNAL_COLUMNS.payload}, '$.completedAt') ${later} ORDER BY later.${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS last_checkpoint_at
|
|
7828
|
+
FROM (SELECT ${JOURNAL_COLUMNS.seq}, ${JOURNAL_COLUMNS.at} FROM ${events} WHERE ${JOURNAL_COLUMNS.runId} = ? ORDER BY ${JOURNAL_COLUMNS.seq} DESC LIMIT 1) AS latest,
|
|
7829
|
+
(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);
|
|
7830
|
+
if (row === undefined)
|
|
7831
|
+
return;
|
|
7832
|
+
return {
|
|
7833
|
+
version: { seq: journalCounter(runId, "seq", row.latest_seq), at: Number(row.latest_at) },
|
|
7834
|
+
snapshot: entryFromRow(row),
|
|
7835
|
+
laterCheckpoints: Number(row.later_checkpoints),
|
|
7836
|
+
...row.last_checkpoint_at === null ? {} : { lastCheckpointAt: Number(row.last_checkpoint_at) }
|
|
7837
|
+
};
|
|
7838
|
+
});
|
|
7839
|
+
}
|
|
7776
7840
|
async requireRun(tx, runId) {
|
|
7777
7841
|
if (await tx.get(`SELECT ${JOURNAL_COLUMNS.runId} FROM ${this.tables.runs} WHERE ${JOURNAL_COLUMNS.runId} = ?`, runId))
|
|
7778
7842
|
return;
|
|
@@ -7990,13 +8054,14 @@ class SqlRunJournal {
|
|
|
7990
8054
|
return this.closePromise;
|
|
7991
8055
|
}
|
|
7992
8056
|
}
|
|
7993
|
-
var STORE_NOW = "CAST(unixepoch('subsec') * 1000 AS INTEGER)";
|
|
8057
|
+
var STORE_NOW = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", EVENT_COLUMNS;
|
|
7994
8058
|
var init_sql_run_journal = __esm(() => {
|
|
7995
8059
|
init_internal();
|
|
7996
8060
|
init_legacy_journal_tables();
|
|
7997
8061
|
init_types();
|
|
7998
8062
|
init_values();
|
|
7999
8063
|
init_internal();
|
|
8064
|
+
EVENT_COLUMNS = [JOURNAL_COLUMNS.runId, JOURNAL_COLUMNS.seq, JOURNAL_COLUMNS.epoch, JOURNAL_COLUMNS.key, JOURNAL_COLUMNS.type, JOURNAL_COLUMNS.payload, JOURNAL_COLUMNS.at];
|
|
8000
8065
|
});
|
|
8001
8066
|
|
|
8002
8067
|
// dist/builtin/workflows/src/durable/journal/resolution.ts
|
|
@@ -8107,7 +8172,13 @@ async function initializeDurableBackend(options = {}) {
|
|
|
8107
8172
|
const selected = owner.selectedBackends;
|
|
8108
8173
|
const existing = selected.get(key);
|
|
8109
8174
|
const entry = existing ?? {
|
|
8110
|
-
ready: openSelectedRunJournal(selection, agentDir).then((journal) => JournalDurableBackend.open(journal, { ownsJournal })).then((opened) => {
|
|
8175
|
+
ready: openSelectedRunJournal(selection, agentDir).then((journal) => JournalDurableBackend.open(journal, { ownsJournal, runs: [] })).then(async (opened) => {
|
|
8176
|
+
try {
|
|
8177
|
+
await opened.hydrateResumableWorkflows();
|
|
8178
|
+
} catch (error) {
|
|
8179
|
+
await opened.close();
|
|
8180
|
+
throw error;
|
|
8181
|
+
}
|
|
8111
8182
|
if (ownsJournal)
|
|
8112
8183
|
opened.closeOnProcessExit();
|
|
8113
8184
|
entry.close = () => opened.close();
|
|
@@ -63754,6 +63825,57 @@ var init_types2 = __esm(() => {
|
|
|
63754
63825
|
});
|
|
63755
63826
|
});
|
|
63756
63827
|
|
|
63828
|
+
// dist/builtin/workflows/src/shared/workflow-infrastructure-error.ts
|
|
63829
|
+
function isInfrastructureError(value2) {
|
|
63830
|
+
if (value2 instanceof WorkflowInfrastructureError)
|
|
63831
|
+
return true;
|
|
63832
|
+
if (typeof value2 !== "object" || value2 === null)
|
|
63833
|
+
return false;
|
|
63834
|
+
const candidate = value2;
|
|
63835
|
+
return candidate.name === WORKFLOW_INFRASTRUCTURE_ERROR_NAME && candidate.retryable === true && typeof candidate.code === "string";
|
|
63836
|
+
}
|
|
63837
|
+
function isRetryableWorkflowError(error) {
|
|
63838
|
+
let current = error;
|
|
63839
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH && current !== undefined && current !== null; depth++) {
|
|
63840
|
+
if (isInfrastructureError(current))
|
|
63841
|
+
return true;
|
|
63842
|
+
current = current instanceof Error ? current.cause : undefined;
|
|
63843
|
+
}
|
|
63844
|
+
return false;
|
|
63845
|
+
}
|
|
63846
|
+
function workflowInfrastructureFault(message) {
|
|
63847
|
+
return FAULT_PATTERNS.find(([pattern]) => pattern.test(message))?.[1];
|
|
63848
|
+
}
|
|
63849
|
+
function asWorkflowInfrastructureError(error) {
|
|
63850
|
+
if (isInfrastructureError(error))
|
|
63851
|
+
return error;
|
|
63852
|
+
if (!(error instanceof Error))
|
|
63853
|
+
return;
|
|
63854
|
+
const code = workflowInfrastructureFault(error.message);
|
|
63855
|
+
return code === undefined ? undefined : new WorkflowInfrastructureError(code, error.message, { cause: error });
|
|
63856
|
+
}
|
|
63857
|
+
var WORKFLOW_INFRASTRUCTURE_ERROR_NAME = "WorkflowInfrastructureError", MAX_CAUSE_DEPTH = 8, FAULT_PATTERNS, WorkflowInfrastructureError;
|
|
63858
|
+
var init_workflow_infrastructure_error = __esm(() => {
|
|
63859
|
+
FAULT_PATTERNS = [
|
|
63860
|
+
[/Local worker (?:process )?cleanup (?:was not confirmed|unconfirmed)/, "worker_cleanup_unconfirmed"],
|
|
63861
|
+
[/Local worker retry limit/, "worker_retry_limit"],
|
|
63862
|
+
[/Local worker (?:startup timed out|exited before readiness)/, "worker_startup_failed"],
|
|
63863
|
+
[/Worker exited before delivery acknowledgement/, "worker_lost"],
|
|
63864
|
+
[/Stale work lease/, "stale_work_lease"],
|
|
63865
|
+
[/Intercom runtime no longer active/, "intercom_unavailable"],
|
|
63866
|
+
[/Storage unavailable/, "storage_unavailable"]
|
|
63867
|
+
];
|
|
63868
|
+
WorkflowInfrastructureError = class WorkflowInfrastructureError extends Error {
|
|
63869
|
+
name = WORKFLOW_INFRASTRUCTURE_ERROR_NAME;
|
|
63870
|
+
retryable = true;
|
|
63871
|
+
code;
|
|
63872
|
+
constructor(code, message, options) {
|
|
63873
|
+
super(message, options);
|
|
63874
|
+
this.code = code;
|
|
63875
|
+
}
|
|
63876
|
+
};
|
|
63877
|
+
});
|
|
63878
|
+
|
|
63757
63879
|
// dist/builtin/workflows/src/workflows/registry.ts
|
|
63758
63880
|
function makeRegistry(store) {
|
|
63759
63881
|
return {
|
|
@@ -63825,11 +63947,13 @@ __export(exports_sdk_surface, {
|
|
|
63825
63947
|
StaleLeaseError: () => StaleLeaseError,
|
|
63826
63948
|
StorageUnavailableError: () => StorageUnavailableError,
|
|
63827
63949
|
WORKFLOW_HEARTBEAT_CUSTOM_TYPE: () => WORKFLOW_HEARTBEAT_CUSTOM_TYPE,
|
|
63950
|
+
WorkflowInfrastructureError: () => WorkflowInfrastructureError,
|
|
63828
63951
|
cancellationRegistry: () => cancellationRegistry,
|
|
63829
63952
|
createAgentSessionAdapter: () => createAgentSessionAdapter,
|
|
63830
63953
|
createCancellationRegistry: () => createCancellationRegistry,
|
|
63831
63954
|
createRegistry: () => createRegistry,
|
|
63832
63955
|
createStore: () => createStore,
|
|
63956
|
+
isRetryableWorkflowError: () => isRetryableWorkflowError,
|
|
63833
63957
|
keepContext: () => keepContext,
|
|
63834
63958
|
loadWorkerWorkflow: () => loadWorkerWorkflow,
|
|
63835
63959
|
normalizeWorkflowName: () => normalizeWorkflowName,
|
|
@@ -63856,6 +63980,7 @@ var init_sdk_surface = __esm(() => {
|
|
|
63856
63980
|
init_worktree();
|
|
63857
63981
|
init_store();
|
|
63858
63982
|
init_types2();
|
|
63983
|
+
init_workflow_infrastructure_error();
|
|
63859
63984
|
init_definitions();
|
|
63860
63985
|
init_registry();
|
|
63861
63986
|
init_types();
|
|
@@ -64308,7 +64433,7 @@ class SqlPoolQueue {
|
|
|
64308
64433
|
});
|
|
64309
64434
|
const row = await this.current(tx, lease, token);
|
|
64310
64435
|
if (row.epoch !== lease.epoch || row.expires_at < now)
|
|
64311
|
-
throw new Error(
|
|
64436
|
+
throw new Error(STALE_WORK_LEASE);
|
|
64312
64437
|
assertSession();
|
|
64313
64438
|
}, action);
|
|
64314
64439
|
}
|
|
@@ -64317,7 +64442,7 @@ class SqlPoolQueue {
|
|
|
64317
64442
|
const { now } = await this.authority(tx, lease);
|
|
64318
64443
|
const row = await this.current(tx, lease, token);
|
|
64319
64444
|
if (row.epoch !== lease.epoch || row.expires_at < now)
|
|
64320
|
-
throw new Error(
|
|
64445
|
+
throw new Error(STALE_WORK_LEASE);
|
|
64321
64446
|
});
|
|
64322
64447
|
}
|
|
64323
64448
|
async enqueue(lease, descriptor, boundary) {
|
|
@@ -64397,7 +64522,7 @@ class SqlPoolQueue {
|
|
|
64397
64522
|
async current(tx, lease, token, allowCompleted = false) {
|
|
64398
64523
|
const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, token.id, lease.runId);
|
|
64399
64524
|
if (row?.state !== "leased" && !(allowCompleted && row?.state === "completed") || row.epoch !== token.epoch || row.generation !== token.generation || row.worker !== token.worker)
|
|
64400
|
-
throw new Error(
|
|
64525
|
+
throw new Error(STALE_WORK_LEASE);
|
|
64401
64526
|
return row;
|
|
64402
64527
|
}
|
|
64403
64528
|
async renew(lease, token, operationId, durationMs) {
|
|
@@ -64410,7 +64535,7 @@ class SqlPoolQueue {
|
|
|
64410
64535
|
const { now } = await this.authority(tx, lease);
|
|
64411
64536
|
const row = await this.current(tx, lease, token);
|
|
64412
64537
|
if (row.epoch !== lease.epoch || row.expires_at < now)
|
|
64413
|
-
throw new Error(
|
|
64538
|
+
throw new Error(STALE_WORK_LEASE);
|
|
64414
64539
|
const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
64415
64540
|
if (previous) {
|
|
64416
64541
|
if (previous.request !== request)
|
|
@@ -64438,7 +64563,7 @@ class SqlPoolQueue {
|
|
|
64438
64563
|
const { now, status } = await this.authority(tx, lease);
|
|
64439
64564
|
const row = await this.current(tx, lease, token);
|
|
64440
64565
|
if (row.epoch !== lease.epoch)
|
|
64441
|
-
throw new Error(
|
|
64566
|
+
throw new Error(STALE_WORK_LEASE);
|
|
64442
64567
|
const previous = await tx.get(`SELECT * FROM ${this.operations} WHERE work = ? AND generation = ? AND operation = ?`, token.id, token.generation, operationId);
|
|
64443
64568
|
if (previous) {
|
|
64444
64569
|
if (previous.request !== request)
|
|
@@ -64446,7 +64571,7 @@ class SqlPoolQueue {
|
|
|
64446
64571
|
return JSON.parse(previous.receipt);
|
|
64447
64572
|
}
|
|
64448
64573
|
if (row.expires_at < now)
|
|
64449
|
-
throw new Error(
|
|
64574
|
+
throw new Error(STALE_WORK_LEASE);
|
|
64450
64575
|
if (!await this.admitsAttemptWrites(tx, lease, status))
|
|
64451
64576
|
throw new Error("Pool root is not running");
|
|
64452
64577
|
const checkpoint = mutation.checkpoint;
|
|
@@ -64486,7 +64611,7 @@ class SqlPoolQueue {
|
|
|
64486
64611
|
const { now, status } = await this.authority(tx, lease);
|
|
64487
64612
|
const row = await this.current(tx, lease, token, true);
|
|
64488
64613
|
if (row.epoch !== lease.epoch)
|
|
64489
|
-
throw new Error(
|
|
64614
|
+
throw new Error(STALE_WORK_LEASE);
|
|
64490
64615
|
if (row.state === "completed") {
|
|
64491
64616
|
const previous = await tx.get(`SELECT result FROM ${this.work}_results WHERE work = ?`, token.id);
|
|
64492
64617
|
if (previous?.result !== payload)
|
|
@@ -64494,7 +64619,7 @@ class SqlPoolQueue {
|
|
|
64494
64619
|
return;
|
|
64495
64620
|
}
|
|
64496
64621
|
if (row.expires_at < now || !await this.admitsAttemptWrites(tx, lease, status))
|
|
64497
|
-
throw new Error(
|
|
64622
|
+
throw new Error(STALE_WORK_LEASE);
|
|
64498
64623
|
if (JSON.parse(payload).runId !== fromRow(row).childRunId)
|
|
64499
64624
|
throw new Error("Pool result identity mismatch");
|
|
64500
64625
|
await tx.run(`INSERT INTO ${this.work}_results VALUES (?, ?)`, token.id, payload);
|
|
@@ -64519,6 +64644,40 @@ class SqlPoolQueue {
|
|
|
64519
64644
|
return true;
|
|
64520
64645
|
});
|
|
64521
64646
|
}
|
|
64647
|
+
async extend(lease, token, durationMs) {
|
|
64648
|
+
positive(durationMs);
|
|
64649
|
+
lease = snapshotLease(lease);
|
|
64650
|
+
token = { ...token };
|
|
64651
|
+
return this.transaction(async (tx) => {
|
|
64652
|
+
const { now } = await this.authority(tx, lease);
|
|
64653
|
+
const row = await this.current(tx, lease, token);
|
|
64654
|
+
if (row.epoch !== lease.epoch)
|
|
64655
|
+
throw new Error(STALE_WORK_LEASE);
|
|
64656
|
+
const expiresAt = Math.max(Number(row.expires_at), expiry(now, durationMs));
|
|
64657
|
+
await tx.run(`UPDATE ${this.work} SET expires_at = ?, renewed_at = ? WHERE id = ?`, expiresAt, now, row.id);
|
|
64658
|
+
return { ...fromRow(row), expiresAt, renewedAt: now };
|
|
64659
|
+
});
|
|
64660
|
+
}
|
|
64661
|
+
async releaseExited(lease, token) {
|
|
64662
|
+
lease = snapshotLease(lease);
|
|
64663
|
+
token = { ...token };
|
|
64664
|
+
return this.transaction(async (tx) => {
|
|
64665
|
+
await this.authority(tx, lease);
|
|
64666
|
+
const row = await tx.get(`SELECT * FROM ${this.work} WHERE id = ? AND root = ?`, token.id, lease.runId);
|
|
64667
|
+
if (row?.state !== "leased" || row.generation !== token.generation || row.worker !== token.worker || row.epoch !== token.epoch)
|
|
64668
|
+
return false;
|
|
64669
|
+
await tx.run(`UPDATE ${this.work} SET state = 'ready', worker = NULL, expires_at = 0 WHERE id = ?`, row.id);
|
|
64670
|
+
return true;
|
|
64671
|
+
});
|
|
64672
|
+
}
|
|
64673
|
+
async releasePreviousIncarnations(lease) {
|
|
64674
|
+
lease = snapshotLease(lease);
|
|
64675
|
+
return this.transaction(async (tx) => {
|
|
64676
|
+
await this.authority(tx, lease);
|
|
64677
|
+
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);
|
|
64678
|
+
return released.changes;
|
|
64679
|
+
});
|
|
64680
|
+
}
|
|
64522
64681
|
async inspect(root) {
|
|
64523
64682
|
return this.transaction(async (tx) => (await tx.all(`SELECT * FROM ${this.work} WHERE root = ? ORDER BY ready_at, rowid`, root)).map(fromRow));
|
|
64524
64683
|
}
|
|
@@ -64529,7 +64688,7 @@ function openSqlPoolQueue(journal) {
|
|
|
64529
64688
|
return Promise.reject(new Error("Worker pool requires a SQL run journal"));
|
|
64530
64689
|
return SqlPoolQueue.open(storage);
|
|
64531
64690
|
}
|
|
64532
|
-
var STORE_NOW2 = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", MAX_WORKER_CLOCK_SKEW_MS = 1000;
|
|
64691
|
+
var STORE_NOW2 = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", MAX_WORKER_CLOCK_SKEW_MS = 1000, STALE_WORK_LEASE = "Stale work lease";
|
|
64533
64692
|
var init_sql_pool_queue = __esm(() => {
|
|
64534
64693
|
init_serializable();
|
|
64535
64694
|
init_boundary_topology();
|
|
@@ -64617,6 +64776,9 @@ var init_host_options = __esm(() => {
|
|
|
64617
64776
|
hostWorkerBindings = Symbol("host-worker-bindings");
|
|
64618
64777
|
});
|
|
64619
64778
|
|
|
64779
|
+
// dist/builtin/workflows/src/workers/protocol.ts
|
|
64780
|
+
var WORKER_HEARTBEAT_INTERVAL_MS = 1000;
|
|
64781
|
+
|
|
64620
64782
|
// dist/builtin/workflows/src/runs/foreground/pending-stage-delivery.ts
|
|
64621
64783
|
function isWorkflowPendingStageDeliveryFailure(error) {
|
|
64622
64784
|
if (error instanceof WorkflowPendingStageDeliveryFailedError)
|
|
@@ -65156,20 +65318,33 @@ var init_stage_handoff = __esm(() => {
|
|
|
65156
65318
|
// dist/builtin/workflows/src/workers/local-pool.ts
|
|
65157
65319
|
import { fork } from "node:child_process";
|
|
65158
65320
|
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
65159
|
-
import {
|
|
65321
|
+
import { createWriteStream } from "node:fs";
|
|
65322
|
+
import { mkdir as mkdir6, rm as rm3, rmdir } from "node:fs/promises";
|
|
65323
|
+
import { dirname as dirname14, join as join29, resolve as resolve13 } from "node:path";
|
|
65160
65324
|
import { setTimeout as delay2 } from "node:timers/promises";
|
|
65161
65325
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
65162
65326
|
import { isBunBinary as isBunBinary2 } from "@bastani/atomic";
|
|
65327
|
+
function workerLogDirectory(journalPath, root) {
|
|
65328
|
+
return join29(dirname14(resolve13(journalPath)), "worker-logs", encodeURIComponent(root).replaceAll(".", "%2E"));
|
|
65329
|
+
}
|
|
65163
65330
|
|
|
65164
65331
|
class LocalWorkerPool {
|
|
65165
65332
|
backend;
|
|
65166
65333
|
options;
|
|
65167
65334
|
children = new Set;
|
|
65168
65335
|
incarnations = new Map;
|
|
65336
|
+
readyWorkers = new Set;
|
|
65337
|
+
logs = new Map;
|
|
65338
|
+
logDirectory;
|
|
65169
65339
|
cleanups = new Set;
|
|
65170
65340
|
recovering;
|
|
65171
65341
|
nextRecoveryAt = 0;
|
|
65172
65342
|
controlAcks = new Map;
|
|
65343
|
+
lastHeard = new Map;
|
|
65344
|
+
lastTick = performance.now();
|
|
65345
|
+
rootStalledMs = 0;
|
|
65346
|
+
ticker;
|
|
65347
|
+
leaseMs;
|
|
65173
65348
|
desiredControl;
|
|
65174
65349
|
root;
|
|
65175
65350
|
store;
|
|
@@ -65193,9 +65368,15 @@ class LocalWorkerPool {
|
|
|
65193
65368
|
this.options = options;
|
|
65194
65369
|
if (!Number.isSafeInteger(options.workers) || options.workers < 1)
|
|
65195
65370
|
throw new Error("Invalid local worker count");
|
|
65371
|
+
if (options.startupTimeoutMs !== undefined && (!Number.isSafeInteger(options.startupTimeoutMs) || options.startupTimeoutMs < 1 || options.startupTimeoutMs > MAX_TIMER_DELAY_MS))
|
|
65372
|
+
throw new Error("Invalid local worker startup timeout");
|
|
65373
|
+
if (options.leaseMs !== undefined && (!Number.isSafeInteger(options.leaseMs) || options.leaseMs < MINIMUM_WORK_LEASE_MS || options.leaseMs > MAX_TIMER_DELAY_MS))
|
|
65374
|
+
throw new Error(`Invalid local worker lease: must be an integer from ${MINIMUM_WORK_LEASE_MS} to ${MAX_TIMER_DELAY_MS} ms`);
|
|
65375
|
+
this.leaseMs = options.leaseMs ?? DEFAULT_WORK_LEASE_MS;
|
|
65196
65376
|
this.releaseBinding = bindChildWorkerDispatcher(backend, this, options.rootId);
|
|
65197
65377
|
if (options.admission && options.rootId === undefined)
|
|
65198
65378
|
workflowResourceAdmission.set(backend, options.admission);
|
|
65379
|
+
this.ticker = setInterval(() => this.observeResponsiveness(), ROOT_TICK_INTERVAL_MS).unref();
|
|
65199
65380
|
}
|
|
65200
65381
|
get workerPids() {
|
|
65201
65382
|
return [...this.children].flatMap((child) => child.pid === undefined ? [] : [child.pid]);
|
|
@@ -65221,6 +65402,7 @@ class LocalWorkerPool {
|
|
|
65221
65402
|
this.lease = { runId: root, holderId: state.holderId, epoch: state.epoch };
|
|
65222
65403
|
const queue = await openSqlPoolQueue(this.backend.journal);
|
|
65223
65404
|
await queue.initialize(this.lease, COORDINATOR_LEASE_MS);
|
|
65405
|
+
await queue.releasePreviousIncarnations(this.lease);
|
|
65224
65406
|
for (;; ) {
|
|
65225
65407
|
const intended = this.desiredControl ?? "running";
|
|
65226
65408
|
await queue.setControl(this.lease, intended);
|
|
@@ -65235,8 +65417,8 @@ class LocalWorkerPool {
|
|
|
65235
65417
|
if (!this.queue || !this.lease)
|
|
65236
65418
|
return;
|
|
65237
65419
|
const control = await this.queue.setControl(this.lease, state);
|
|
65238
|
-
const deadline = Date.now() +
|
|
65239
|
-
while ([...this.
|
|
65420
|
+
const deadline = Date.now() + CONTROL_ACKNOWLEDGEMENT_TIMEOUT_MS;
|
|
65421
|
+
while ([...this.readyWorkers].some((worker) => (this.controlAcks.get(worker) ?? -1) < control.revision)) {
|
|
65240
65422
|
if (this.desiredControl !== state)
|
|
65241
65423
|
return;
|
|
65242
65424
|
if (Date.now() >= deadline) {
|
|
@@ -65306,7 +65488,16 @@ class LocalWorkerPool {
|
|
|
65306
65488
|
root,
|
|
65307
65489
|
holder: "coordinator"
|
|
65308
65490
|
});
|
|
65309
|
-
|
|
65491
|
+
this.logDirectory = workerLogDirectory(this.options.journalPath, root);
|
|
65492
|
+
await mkdir6(this.logDirectory, { recursive: true }).catch(() => {
|
|
65493
|
+
return;
|
|
65494
|
+
});
|
|
65495
|
+
const workers = Array.from({ length: this.options.workers }, () => this.spawn(root));
|
|
65496
|
+
try {
|
|
65497
|
+
await Promise.any(workers);
|
|
65498
|
+
} catch (error) {
|
|
65499
|
+
throw error.errors[0];
|
|
65500
|
+
}
|
|
65310
65501
|
}
|
|
65311
65502
|
spawn(root) {
|
|
65312
65503
|
if (this.closed)
|
|
@@ -65327,26 +65518,56 @@ class LocalWorkerPool {
|
|
|
65327
65518
|
let serial = Promise.resolve();
|
|
65328
65519
|
let work;
|
|
65329
65520
|
const deliveries = new Map;
|
|
65521
|
+
const logPath = join29(this.logDirectory, `${worker}.log`);
|
|
65522
|
+
this.logs.set(child, logPath);
|
|
65523
|
+
let logFailure;
|
|
65524
|
+
const log = createWriteStream(logPath, { flags: "a" });
|
|
65525
|
+
log.on("error", (error) => {
|
|
65526
|
+
logFailure = error.message;
|
|
65527
|
+
});
|
|
65330
65528
|
let stderr = "";
|
|
65331
65529
|
child.stderr?.on("data", (chunk) => {
|
|
65332
|
-
stderr = (stderr + chunk.toString()).slice(-
|
|
65530
|
+
stderr = (stderr + chunk.toString()).slice(-STDERR_TAIL_CHARACTERS);
|
|
65531
|
+
});
|
|
65532
|
+
child.stderr?.on("error", (error) => {
|
|
65533
|
+
logFailure ??= error.message;
|
|
65534
|
+
log.end();
|
|
65333
65535
|
});
|
|
65536
|
+
child.stderr?.pipe(log);
|
|
65537
|
+
const diagnosed = (summary) => new Error(`${summary} (worker stderr log: ${logFailure === undefined ? logPath : `unavailable, ${logFailure}`})${stderr ? `: ${stderr}` : ""}`);
|
|
65538
|
+
const startupTimeoutMs = this.options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
65539
|
+
let timedOut = false;
|
|
65540
|
+
let terminated = false;
|
|
65541
|
+
const terminate = () => {
|
|
65542
|
+
if (terminated)
|
|
65543
|
+
return;
|
|
65544
|
+
terminated = true;
|
|
65545
|
+
child.kill("SIGKILL");
|
|
65546
|
+
};
|
|
65547
|
+
const replied = (error) => {
|
|
65548
|
+
if (error)
|
|
65549
|
+
terminate();
|
|
65550
|
+
};
|
|
65334
65551
|
return new Promise((resolve, reject) => {
|
|
65335
65552
|
const startup = setTimeout(() => {
|
|
65336
|
-
|
|
65337
|
-
|
|
65338
|
-
|
|
65339
|
-
|
|
65340
|
-
child.once("error", (error) => {
|
|
65553
|
+
timedOut = true;
|
|
65554
|
+
terminate();
|
|
65555
|
+
}, startupTimeoutMs);
|
|
65556
|
+
child.on("error", (error) => {
|
|
65341
65557
|
clearTimeout(startup);
|
|
65342
65558
|
reject(error);
|
|
65559
|
+
terminate();
|
|
65343
65560
|
});
|
|
65561
|
+
const closed = new Promise((resolve) => child.once("close", () => resolve()));
|
|
65344
65562
|
child.once("exit", () => {
|
|
65563
|
+
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")));
|
|
65345
65564
|
this.children.delete(child);
|
|
65565
|
+
this.logs.delete(child);
|
|
65346
65566
|
clearTimeout(startup);
|
|
65347
65567
|
this.incarnations.delete(worker);
|
|
65348
|
-
|
|
65568
|
+
this.readyWorkers.delete(worker);
|
|
65349
65569
|
this.controlAcks.delete(worker);
|
|
65570
|
+
this.lastHeard.delete(worker);
|
|
65350
65571
|
if (work)
|
|
65351
65572
|
this.handoff?.fence(work);
|
|
65352
65573
|
for (const delivery of deliveries.values())
|
|
@@ -65369,9 +65590,11 @@ class LocalWorkerPool {
|
|
|
65369
65590
|
}
|
|
65370
65591
|
if (this.closed)
|
|
65371
65592
|
return;
|
|
65593
|
+
if (work)
|
|
65594
|
+
await this.queue.releaseExited(this.lease, work);
|
|
65372
65595
|
const exhausted = work ? work.generation >= 3 : ++this.replacements > 3;
|
|
65373
65596
|
if (exhausted)
|
|
65374
|
-
this.failure =
|
|
65597
|
+
this.failure = diagnosed("Local worker retry limit");
|
|
65375
65598
|
else
|
|
65376
65599
|
await this.spawn(root);
|
|
65377
65600
|
}).catch((error) => {
|
|
@@ -65381,6 +65604,8 @@ class LocalWorkerPool {
|
|
|
65381
65604
|
cleanup.finally(() => this.cleanups.delete(cleanup));
|
|
65382
65605
|
});
|
|
65383
65606
|
child.on("message", (message) => {
|
|
65607
|
+
this.observeResponsiveness();
|
|
65608
|
+
this.lastHeard.set(worker, { at: performance.now(), rootStalled: this.rootStalledMs });
|
|
65384
65609
|
if (message.kind === "delivery-ack") {
|
|
65385
65610
|
const pending = deliveries.get(message.deliveryId);
|
|
65386
65611
|
deliveries.delete(message.deliveryId);
|
|
@@ -65392,7 +65617,10 @@ class LocalWorkerPool {
|
|
|
65392
65617
|
}
|
|
65393
65618
|
const response = serial.then(async () => {
|
|
65394
65619
|
if (message.kind === "ready") {
|
|
65620
|
+
if (terminated)
|
|
65621
|
+
return;
|
|
65395
65622
|
ready = true;
|
|
65623
|
+
this.readyWorkers.add(worker);
|
|
65396
65624
|
clearTimeout(startup);
|
|
65397
65625
|
resolve();
|
|
65398
65626
|
return;
|
|
@@ -65419,11 +65647,13 @@ class LocalWorkerPool {
|
|
|
65419
65647
|
work = await queue.claim(lease, worker, this.sources.map((source) => ({
|
|
65420
65648
|
definition: `${source.path}#${source.exportName}`,
|
|
65421
65649
|
digest: source.digest
|
|
65422
|
-
})),
|
|
65650
|
+
})), this.leaseMs);
|
|
65423
65651
|
return work;
|
|
65424
65652
|
}
|
|
65425
65653
|
if (!work)
|
|
65426
65654
|
throw new Error("Worker has no active attempt");
|
|
65655
|
+
if (message.kind === "renew" || work.expiresAt - Date.now() < this.leaseMs / 2)
|
|
65656
|
+
work = await queue.extend(lease, work, this.leaseMs);
|
|
65427
65657
|
if (message.kind === "activity")
|
|
65428
65658
|
return this.handoff?.publish(work, message.runs);
|
|
65429
65659
|
if (message.kind === "route")
|
|
@@ -65444,10 +65674,8 @@ class LocalWorkerPool {
|
|
|
65444
65674
|
});
|
|
65445
65675
|
}));
|
|
65446
65676
|
}
|
|
65447
|
-
if (message.kind === "renew")
|
|
65448
|
-
work = await queue.renew(lease, work, randomUUID17(), WORK_LEASE_MS);
|
|
65677
|
+
if (message.kind === "renew")
|
|
65449
65678
|
return;
|
|
65450
|
-
}
|
|
65451
65679
|
if (message.kind === "commit") {
|
|
65452
65680
|
const receipt = await queue.commit(lease, work, message.operation, message.mutation);
|
|
65453
65681
|
this.usageTotal = await this.usageLedger.total(root);
|
|
@@ -65472,13 +65700,7 @@ class LocalWorkerPool {
|
|
|
65472
65700
|
});
|
|
65473
65701
|
if (message.kind !== "delivery" && message.kind !== "delivery-ready")
|
|
65474
65702
|
serial = response.then(() => {}, () => {});
|
|
65475
|
-
response.then((value2) => {
|
|
65476
|
-
if (child.connected)
|
|
65477
|
-
child.send({ id: message.id, value: value2 });
|
|
65478
|
-
}, (error) => {
|
|
65479
|
-
if (child.connected)
|
|
65480
|
-
child.send({ id: message.id, error: error.message });
|
|
65481
|
-
});
|
|
65703
|
+
response.then((value2) => child.send({ id: message.id, value: value2 }, replied), (error) => child.send({ id: message.id, error: error.message }, replied));
|
|
65482
65704
|
});
|
|
65483
65705
|
});
|
|
65484
65706
|
}
|
|
@@ -65488,14 +65710,22 @@ class LocalWorkerPool {
|
|
|
65488
65710
|
if (this.closed || performance.now() < this.nextRecoveryAt)
|
|
65489
65711
|
return Promise.resolve();
|
|
65490
65712
|
this.recovering = (async () => {
|
|
65713
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
65491
65714
|
await this.admission?.reconcile();
|
|
65492
65715
|
const expiredBefore = Date.now();
|
|
65493
65716
|
for (const work of await this.queue.inspect(root)) {
|
|
65494
65717
|
if (work.state !== "leased" || work.expiresAt >= expiredBefore)
|
|
65495
65718
|
continue;
|
|
65496
65719
|
const child = work.worker === null ? undefined : this.incarnations.get(work.worker);
|
|
65497
|
-
if (child)
|
|
65498
|
-
await this.
|
|
65720
|
+
if (child && work.worker !== null && this.isLive(work.worker, child)) {
|
|
65721
|
+
await this.queue.extend(this.lease, work, this.leaseMs).catch((error) => {
|
|
65722
|
+
if (error.message !== STALE_WORK_LEASE)
|
|
65723
|
+
throw error;
|
|
65724
|
+
});
|
|
65725
|
+
continue;
|
|
65726
|
+
}
|
|
65727
|
+
if (child && !await this.stop(child).then(() => true, () => false))
|
|
65728
|
+
continue;
|
|
65499
65729
|
await this.queue.expire(this.lease, work);
|
|
65500
65730
|
}
|
|
65501
65731
|
})().finally(() => {
|
|
@@ -65504,6 +65734,18 @@ class LocalWorkerPool {
|
|
|
65504
65734
|
});
|
|
65505
65735
|
return this.recovering;
|
|
65506
65736
|
}
|
|
65737
|
+
observeResponsiveness() {
|
|
65738
|
+
const now = performance.now();
|
|
65739
|
+
const gap = now - this.lastTick;
|
|
65740
|
+
if (gap > ROOT_STALL_THRESHOLD_MS)
|
|
65741
|
+
this.rootStalledMs += gap - ROOT_TICK_INTERVAL_MS;
|
|
65742
|
+
this.lastTick = now;
|
|
65743
|
+
}
|
|
65744
|
+
isLive(worker, child) {
|
|
65745
|
+
this.observeResponsiveness();
|
|
65746
|
+
const heard = this.lastHeard.get(worker);
|
|
65747
|
+
return child.exitCode === null && child.signalCode === null && child.connected && heard !== undefined && performance.now() - heard.at - (this.rootStalledMs - heard.rootStalled) < this.leaseMs;
|
|
65748
|
+
}
|
|
65507
65749
|
stop(child) {
|
|
65508
65750
|
if (child.pid === undefined || child.exitCode !== null || child.signalCode !== null)
|
|
65509
65751
|
return Promise.resolve();
|
|
@@ -65520,9 +65762,13 @@ class LocalWorkerPool {
|
|
|
65520
65762
|
try {
|
|
65521
65763
|
return await this.dispatch(definition, inputs, options);
|
|
65522
65764
|
} catch (error) {
|
|
65523
|
-
|
|
65524
|
-
|
|
65525
|
-
|
|
65765
|
+
try {
|
|
65766
|
+
if (this.desiredControl !== "quit" || !findWorkflowGracefulQuit(error))
|
|
65767
|
+
await this.close();
|
|
65768
|
+
} catch (closeError) {
|
|
65769
|
+
throw asWorkflowInfrastructureError(closeError) ?? closeError;
|
|
65770
|
+
}
|
|
65771
|
+
throw asWorkflowInfrastructureError(error) ?? error;
|
|
65526
65772
|
}
|
|
65527
65773
|
}
|
|
65528
65774
|
async dispatch(definition, inputs, options) {
|
|
@@ -65566,6 +65812,8 @@ class LocalWorkerPool {
|
|
|
65566
65812
|
for (;; ) {
|
|
65567
65813
|
options.signal?.throwIfAborted();
|
|
65568
65814
|
if (this.closed) {
|
|
65815
|
+
if (this.failure)
|
|
65816
|
+
throw this.failure;
|
|
65569
65817
|
if (this.desiredControl === "quit")
|
|
65570
65818
|
throw new WorkflowGracefulQuitError(root, "worker pool teardown");
|
|
65571
65819
|
throw new Error("Local worker pool is closed");
|
|
@@ -65592,19 +65840,28 @@ class LocalWorkerPool {
|
|
|
65592
65840
|
}
|
|
65593
65841
|
async dispose() {
|
|
65594
65842
|
this.closed = true;
|
|
65843
|
+
clearInterval(this.ticker);
|
|
65595
65844
|
this.releaseBinding();
|
|
65596
65845
|
if (this.options.rootId === undefined)
|
|
65597
65846
|
workflowResourceAdmission.delete(this.backend);
|
|
65598
65847
|
let failure;
|
|
65848
|
+
let stopping = [];
|
|
65599
65849
|
try {
|
|
65600
65850
|
await this.recovering?.catch(() => {});
|
|
65601
|
-
|
|
65851
|
+
stopping = [...this.children].map((child) => ({ child, log: this.logs.get(child) }));
|
|
65852
|
+
await Promise.all(stopping.map(({ child }) => this.stop(child)));
|
|
65602
65853
|
await Promise.all([...this.cleanups]);
|
|
65603
65854
|
if (this.cleanupFailure)
|
|
65604
65855
|
throw this.cleanupFailure;
|
|
65605
65856
|
} catch (error) {
|
|
65606
65857
|
failure = error;
|
|
65607
65858
|
}
|
|
65859
|
+
if (failure === undefined) {
|
|
65860
|
+
const stopped = stopping.flatMap(({ child, log }) => log !== undefined && (child.exitCode !== null || child.signalCode !== null) ? [log] : []);
|
|
65861
|
+
await Promise.all(stopped.map((log) => rm3(log, { force: true }).catch(() => {})));
|
|
65862
|
+
if (this.logDirectory !== undefined)
|
|
65863
|
+
await rmdir(this.logDirectory).catch(() => {});
|
|
65864
|
+
}
|
|
65608
65865
|
try {
|
|
65609
65866
|
await this.releaseRoutes?.();
|
|
65610
65867
|
} catch (error) {
|
|
@@ -65614,7 +65871,7 @@ class LocalWorkerPool {
|
|
|
65614
65871
|
throw failure;
|
|
65615
65872
|
}
|
|
65616
65873
|
}
|
|
65617
|
-
var INTERNAL_WORKFLOW_WORKER_ARG = "--internal-workflow-worker",
|
|
65874
|
+
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;
|
|
65618
65875
|
var init_local_pool = __esm(() => {
|
|
65619
65876
|
init_internal();
|
|
65620
65877
|
init_sql_pool_queue();
|
|
@@ -65622,12 +65879,14 @@ var init_local_pool = __esm(() => {
|
|
|
65622
65879
|
init_sql_run_journal();
|
|
65623
65880
|
init_workflow_tool_abort();
|
|
65624
65881
|
init_sdk_intercom();
|
|
65882
|
+
init_workflow_infrastructure_error();
|
|
65625
65883
|
init_admission_binding();
|
|
65626
65884
|
init_definitions();
|
|
65627
65885
|
init_dispatch();
|
|
65628
65886
|
init_host_options();
|
|
65629
65887
|
init_resource_admission();
|
|
65630
65888
|
init_stage_handoff();
|
|
65889
|
+
MINIMUM_WORK_LEASE_MS = 2 * WORKER_HEARTBEAT_INTERVAL_MS;
|
|
65631
65890
|
COORDINATOR_LEASE_MS = 3 * STAGE_SESSION_HEARTBEAT_INTERVAL_MS;
|
|
65632
65891
|
});
|
|
65633
65892
|
|
|
@@ -65679,6 +65938,8 @@ async function activatePublicPool(backend, options) {
|
|
|
65679
65938
|
const cwd = options.cwd ?? process.cwd();
|
|
65680
65939
|
const localWorkers = options.localWorkers && {
|
|
65681
65940
|
...options.localWorkers,
|
|
65941
|
+
startupTimeoutMs: undefined,
|
|
65942
|
+
leaseMs: undefined,
|
|
65682
65943
|
definitions: options.localWorkers.definitions.map((source) => ({ ...source, path: resolve14(cwd, source.path) }))
|
|
65683
65944
|
};
|
|
65684
65945
|
const admission = options.admission && {
|
|
@@ -65707,7 +65968,9 @@ async function activatePublicPool(backend, options) {
|
|
|
65707
65968
|
journalPath: backend.journal.path,
|
|
65708
65969
|
workers: localWorkers.count,
|
|
65709
65970
|
definitions,
|
|
65710
|
-
admission: resources.admission ?? {}
|
|
65971
|
+
admission: resources.admission ?? {},
|
|
65972
|
+
startupTimeoutMs: options.localWorkers?.startupTimeoutMs,
|
|
65973
|
+
leaseMs: options.localWorkers?.leaseMs
|
|
65711
65974
|
});
|
|
65712
65975
|
try {
|
|
65713
65976
|
pool.validateOptions(options);
|
|
@@ -66625,12 +66888,12 @@ function createChildWorkflowRunner(input) {
|
|
|
66625
66888
|
const childExitStatus = isWorkflowExitStatus2(childRun.status) ? childRun.status : "blocked";
|
|
66626
66889
|
if (!isWorkflowExitStatus2(childRun.status) && !childBudgetExceeded || childRun.status === "failed" && childRun.exited !== true) {
|
|
66627
66890
|
const failedChildStage = childRun.stages.find((stage) => stage.failureKind !== undefined);
|
|
66628
|
-
|
|
66629
|
-
|
|
66630
|
-
|
|
66631
|
-
|
|
66632
|
-
|
|
66633
|
-
});
|
|
66891
|
+
const message = `atomic-workflows: child workflow "${childName}" (${child.name}) failed with status ${childRun.status}${childRun.error !== undefined ? `: ${childRun.error}` : ""}`;
|
|
66892
|
+
const cause = {
|
|
66893
|
+
...failedChildStage?.failureKind !== undefined ? { code: failedChildStage.failureKind } : {},
|
|
66894
|
+
...failedChildStage?.failureMessage !== undefined ? { message: failedChildStage.failureMessage } : {}
|
|
66895
|
+
};
|
|
66896
|
+
throw new Error(message, { cause });
|
|
66634
66897
|
}
|
|
66635
66898
|
const outputs = selectWorkflowOutputs(child, childRun.result);
|
|
66636
66899
|
const childExited = childBudgetExceeded || childRun.exited === true || childRun.status !== "completed";
|
|
@@ -66691,7 +66954,7 @@ function describeErrorWithCauses(error) {
|
|
|
66691
66954
|
const messages = [];
|
|
66692
66955
|
const visited = new Set;
|
|
66693
66956
|
let current = error;
|
|
66694
|
-
for (let depth = 0;current !== undefined && depth <
|
|
66957
|
+
for (let depth = 0;current !== undefined && depth < MAX_CAUSE_DEPTH2 && !visited.has(current); depth++) {
|
|
66695
66958
|
visited.add(current);
|
|
66696
66959
|
const message = current instanceof Error ? current.message : String(current);
|
|
66697
66960
|
if (!messages.includes(message))
|
|
@@ -66700,7 +66963,7 @@ function describeErrorWithCauses(error) {
|
|
|
66700
66963
|
}
|
|
66701
66964
|
return messages.join(": ");
|
|
66702
66965
|
}
|
|
66703
|
-
var
|
|
66966
|
+
var MAX_CAUSE_DEPTH2 = 5;
|
|
66704
66967
|
|
|
66705
66968
|
// dist/builtin/workflows/src/engine/run-durable-finalize.ts
|
|
66706
66969
|
async function finalizeDurableTerminalStatus(input) {
|
|
@@ -67220,7 +67483,7 @@ function recordedOwners(boundary, reason) {
|
|
|
67220
67483
|
const pending = [{ value: reason, depth: 0 }];
|
|
67221
67484
|
while (pending.length > 0) {
|
|
67222
67485
|
const { value: value2, depth } = pending.pop();
|
|
67223
|
-
if (depth >
|
|
67486
|
+
if (depth > MAX_CAUSE_DEPTH3)
|
|
67224
67487
|
continue;
|
|
67225
67488
|
if (isPrimitive(value2)) {
|
|
67226
67489
|
if (depth === 0 || value2 !== undefined && value2 !== null) {
|
|
@@ -67542,7 +67805,7 @@ function containUiRejections(ui, scope) {
|
|
|
67542
67805
|
custom: (factory, options) => scope.watch(ui.custom(factory, options))
|
|
67543
67806
|
};
|
|
67544
67807
|
}
|
|
67545
|
-
var EVENT = "unhandledRejection", BOUNDARY_KEY, FLAG = "--unhandled-rejections",
|
|
67808
|
+
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;
|
|
67546
67809
|
var init_run_rejection_boundary = __esm(() => {
|
|
67547
67810
|
init_prompt_callsite();
|
|
67548
67811
|
init_workflow_source();
|
|
@@ -72290,8 +72553,8 @@ var init_stage_runner_controller = __esm(() => {
|
|
|
72290
72553
|
|
|
72291
72554
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts
|
|
72292
72555
|
import { createHash as createHash4 } from "node:crypto";
|
|
72293
|
-
import { mkdir as
|
|
72294
|
-
import { basename as basename5, dirname as
|
|
72556
|
+
import { mkdir as mkdir7, writeFile as writeFile10 } from "node:fs/promises";
|
|
72557
|
+
import { basename as basename5, dirname as dirname15, isAbsolute as isAbsolute11, join as join30, resolve as resolve15 } from "node:path";
|
|
72295
72558
|
function normalizeMaxOutput2(maxOutput) {
|
|
72296
72559
|
return {
|
|
72297
72560
|
bytes: maxOutput?.bytes ?? DEFAULT_MAX_OUTPUT_BYTES,
|
|
@@ -72354,7 +72617,7 @@ function formatByteSize(bytes) {
|
|
|
72354
72617
|
}
|
|
72355
72618
|
function transcriptPath(runId, outputPath) {
|
|
72356
72619
|
const digest = createHash4("sha256").update(outputPath).digest("hex").slice(0, 16);
|
|
72357
|
-
return
|
|
72620
|
+
return join30(workflowArtifactRunPath(runId), "transcripts", `${digest}-${basename5(outputPath)}.transcript.md`);
|
|
72358
72621
|
}
|
|
72359
72622
|
function appendContent(lines, content) {
|
|
72360
72623
|
if (typeof content === "string") {
|
|
@@ -72474,7 +72737,7 @@ async function finalizePromptOutput(fullOutput, outputOptions, runtimeCwd, runId
|
|
|
72474
72737
|
const transcriptFile = transcriptPath(runId, outputPath);
|
|
72475
72738
|
const transcript = renderTranscript(messages, fullOutput);
|
|
72476
72739
|
try {
|
|
72477
|
-
await
|
|
72740
|
+
await mkdir7(dirname15(outputPath), { recursive: true });
|
|
72478
72741
|
await writeFile10(outputPath, fullOutput, "utf8");
|
|
72479
72742
|
} catch (err) {
|
|
72480
72743
|
return `${displayOutput}
|
|
@@ -72486,7 +72749,7 @@ ${err instanceof Error ? err.message : String(err)}`;
|
|
|
72486
72749
|
let transcriptError;
|
|
72487
72750
|
try {
|
|
72488
72751
|
await ensureWorkflowArtifactRunDirectory(runId);
|
|
72489
|
-
await
|
|
72752
|
+
await mkdir7(dirname15(transcriptFile), { recursive: true });
|
|
72490
72753
|
await writeFile10(transcriptFile, transcript, "utf8");
|
|
72491
72754
|
transcriptAvailable = true;
|
|
72492
72755
|
} catch (err) {
|
|
@@ -73395,7 +73658,7 @@ function reportsClosedSession(error) {
|
|
|
73395
73658
|
}
|
|
73396
73659
|
function isSessionClosedError(error) {
|
|
73397
73660
|
let current = error;
|
|
73398
|
-
for (let depth = 0;depth <
|
|
73661
|
+
for (let depth = 0;depth < MAX_CAUSE_DEPTH4 && current !== undefined; depth++) {
|
|
73399
73662
|
try {
|
|
73400
73663
|
if (reportsClosedSession(current))
|
|
73401
73664
|
return true;
|
|
@@ -73406,7 +73669,7 @@ function isSessionClosedError(error) {
|
|
|
73406
73669
|
}
|
|
73407
73670
|
return false;
|
|
73408
73671
|
}
|
|
73409
|
-
var
|
|
73672
|
+
var MAX_CAUSE_DEPTH4 = 8;
|
|
73410
73673
|
var init_session_closed_error = () => {};
|
|
73411
73674
|
|
|
73412
73675
|
// dist/builtin/workflows/src/engine/workflow-activity.ts
|
|
@@ -88486,7 +88749,7 @@ function installCompactionHook(api, store) {
|
|
|
88486
88749
|
});
|
|
88487
88750
|
}
|
|
88488
88751
|
// dist/builtin/workflows/src/extension/config-loader.ts
|
|
88489
|
-
import { isAbsolute as isAbsolute12, join as
|
|
88752
|
+
import { isAbsolute as isAbsolute12, join as join31 } from "node:path";
|
|
88490
88753
|
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME2, getAgentDir as getAgentDir6 } from "@bastani/atomic";
|
|
88491
88754
|
// dist/builtin/workflows/src/extension/lifecycle-notifications.ts
|
|
88492
88755
|
init_returned_run_status();
|
|
@@ -89403,7 +89666,7 @@ function resolveWorkflowPaths(workflows, baseDir) {
|
|
|
89403
89666
|
}
|
|
89404
89667
|
return Object.fromEntries(Object.entries(workflows).map(([name, entry]) => [
|
|
89405
89668
|
name,
|
|
89406
|
-
isAbsolute12(entry.path) ? entry.path :
|
|
89669
|
+
isAbsolute12(entry.path) ? entry.path : join31(baseDir, entry.path)
|
|
89407
89670
|
]));
|
|
89408
89671
|
}
|
|
89409
89672
|
function workflowAgentDirs(opts) {
|
|
@@ -89411,12 +89674,12 @@ function workflowAgentDirs(opts) {
|
|
|
89411
89674
|
return opts.agentDirs;
|
|
89412
89675
|
if (opts.homeDir !== undefined) {
|
|
89413
89676
|
const homeDir = opts.homeDir;
|
|
89414
|
-
return [
|
|
89677
|
+
return [join31(homeDir, CONFIG_DIR_NAME2, "agent")];
|
|
89415
89678
|
}
|
|
89416
89679
|
return [getAgentDir6()];
|
|
89417
89680
|
}
|
|
89418
89681
|
function toScopedDiscoveryConfig(globalConfig, projectConfig, opts) {
|
|
89419
|
-
const globalBase = opts.agentDir ?? (opts.homeDir === undefined ? getAgentDir6() :
|
|
89682
|
+
const globalBase = opts.agentDir ?? (opts.homeDir === undefined ? getAgentDir6() : join31(opts.homeDir, CONFIG_DIR_NAME2, "agent"));
|
|
89420
89683
|
const projectBase = opts.projectRoot;
|
|
89421
89684
|
const result = {};
|
|
89422
89685
|
const projectWorkflows = resolveWorkflowPaths(projectConfig?.workflows, projectBase);
|
|
@@ -89426,7 +89689,7 @@ function toScopedDiscoveryConfig(globalConfig, projectConfig, opts) {
|
|
|
89426
89689
|
if (hasWorkflows(globalConfig)) {
|
|
89427
89690
|
const projectKeys = new Set(Object.keys(projectWorkflows ?? {}));
|
|
89428
89691
|
const globalEntries = Object.entries(globalConfig.workflows).filter(([name]) => !projectKeys.has(name)).map(([name, entry]) => {
|
|
89429
|
-
return [name, isAbsolute12(entry.path) ? entry.path :
|
|
89692
|
+
return [name, isAbsolute12(entry.path) ? entry.path : join31(globalBase, entry.path)];
|
|
89430
89693
|
});
|
|
89431
89694
|
if (globalEntries.length > 0) {
|
|
89432
89695
|
result.globalWorkflows = Object.fromEntries(globalEntries);
|
|
@@ -89437,8 +89700,8 @@ function toScopedDiscoveryConfig(globalConfig, projectConfig, opts) {
|
|
|
89437
89700
|
async function loadWorkflowConfig(opts = {}) {
|
|
89438
89701
|
const projectRoot = opts.projectRoot ?? process.cwd();
|
|
89439
89702
|
const diagnostics = [];
|
|
89440
|
-
const globalCandidates = workflowAgentDirs(opts).map((agentDir) =>
|
|
89441
|
-
const projectCandidates = [
|
|
89703
|
+
const globalCandidates = workflowAgentDirs(opts).map((agentDir) => join31(agentDir, "extensions", "workflow", "config.json"));
|
|
89704
|
+
const projectCandidates = [join31(projectRoot, CONFIG_DIR_NAME2, "extensions", "workflow", "config.json")];
|
|
89442
89705
|
let globalConfig = null;
|
|
89443
89706
|
for (let i = globalCandidates.length - 1;i >= 0; i--) {
|
|
89444
89707
|
const globalPath = globalCandidates[i];
|
|
@@ -91094,7 +91357,7 @@ init_possible_stages();
|
|
|
91094
91357
|
import { registerExtensionContextRetirementEffect as registerExtensionContextRetirementEffect2 } from "@bastani/atomic";
|
|
91095
91358
|
|
|
91096
91359
|
// dist/builtin/workflows/src/extension/discovery.ts
|
|
91097
|
-
import { join as
|
|
91360
|
+
import { join as join33 } from "node:path";
|
|
91098
91361
|
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME3, getAgentDir as getAgentDir7 } from "@bastani/atomic";
|
|
91099
91362
|
|
|
91100
91363
|
// dist/builtin/workflows/builtin/index.ts
|
|
@@ -91115,12 +91378,12 @@ init_registry();
|
|
|
91115
91378
|
// dist/builtin/workflows/src/extension/discovery-loaders.ts
|
|
91116
91379
|
init_workflow_module_loader();
|
|
91117
91380
|
import { readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
91118
|
-
import { extname, isAbsolute as isAbsolute13, join as
|
|
91381
|
+
import { extname, isAbsolute as isAbsolute13, join as join32, resolve as resolve17 } from "node:path";
|
|
91119
91382
|
async function scanWorkflowDir(dir) {
|
|
91120
91383
|
try {
|
|
91121
91384
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
91122
91385
|
const WORKFLOW_EXTS = new Set([".ts", ".js", ".mjs", ".cjs"]);
|
|
91123
|
-
return entries.filter((e) => e.isFile() && WORKFLOW_EXTS.has(extname(e.name))).map((e) =>
|
|
91386
|
+
return entries.filter((e) => e.isFile() && WORKFLOW_EXTS.has(extname(e.name))).map((e) => join32(dir, e.name)).sort();
|
|
91124
91387
|
} catch {
|
|
91125
91388
|
return null;
|
|
91126
91389
|
}
|
|
@@ -91190,7 +91453,7 @@ function workflowAgentDirs2(options) {
|
|
|
91190
91453
|
return options.agentDirs;
|
|
91191
91454
|
if (options?.homeDir !== undefined) {
|
|
91192
91455
|
const homeDir = options.homeDir;
|
|
91193
|
-
return [
|
|
91456
|
+
return [join33(homeDir, CONFIG_DIR_NAME3, "agent")];
|
|
91194
91457
|
}
|
|
91195
91458
|
return [getAgentDir7()];
|
|
91196
91459
|
}
|
|
@@ -91346,7 +91609,7 @@ async function discoverWorkflows(options) {
|
|
|
91346
91609
|
registry = await applyBatch(candidates, registry, sources, diagnostics);
|
|
91347
91610
|
}
|
|
91348
91611
|
}
|
|
91349
|
-
for (const dir of [
|
|
91612
|
+
for (const dir of [join33(cwd, CONFIG_DIR_NAME3, "workflows")]) {
|
|
91350
91613
|
const candidates = await loadFromDir(dir, "project-local", diagnostics, getWorkflowHostModules);
|
|
91351
91614
|
registry = await applyBatch(candidates, registry, sources, diagnostics);
|
|
91352
91615
|
}
|
|
@@ -91358,7 +91621,7 @@ async function discoverWorkflows(options) {
|
|
|
91358
91621
|
registry = await applyBatch(candidates, registry, sources, diagnostics);
|
|
91359
91622
|
}
|
|
91360
91623
|
}
|
|
91361
|
-
for (const dir of agentDirs.map((agentDir) =>
|
|
91624
|
+
for (const dir of agentDirs.map((agentDir) => join33(agentDir, "workflows")).reverse()) {
|
|
91362
91625
|
const candidates = await loadFromDir(dir, "user-global", diagnostics, getWorkflowHostModules);
|
|
91363
91626
|
registry = await applyBatch(candidates, registry, sources, diagnostics);
|
|
91364
91627
|
}
|
|
@@ -91959,6 +92222,8 @@ function createDurableResumeRuntime(deps) {
|
|
|
91959
92222
|
try {
|
|
91960
92223
|
await backend.hydrateResumableWorkflows();
|
|
91961
92224
|
await hydrateStoredWorkflowCandidates(backend);
|
|
92225
|
+
for (const entry of backend.listCompletedWorkflows())
|
|
92226
|
+
await backend.hydrateWorkflow(entry.workflowId);
|
|
91962
92227
|
return await listOpenableCompletedWorkflows(backend, deps.adapters?.sessionStore);
|
|
91963
92228
|
} finally {
|
|
91964
92229
|
purgeSuppressedWorkflowRuns(backend, deps.store, deps.toolControlRegistry);
|
|
@@ -91969,8 +92234,11 @@ function createDurableResumeRuntime(deps) {
|
|
|
91969
92234
|
const finish = workflowObservationRuntime(deps.store).beginRecovery();
|
|
91970
92235
|
try {
|
|
91971
92236
|
const backend = selectedBackend(workflowId);
|
|
91972
|
-
const entry = resolveCatalogEntry(workflowId, catalog ??
|
|
91973
|
-
const
|
|
92237
|
+
const entry = resolveCatalogEntry(workflowId, catalog ?? backend.listCompletedWorkflows());
|
|
92238
|
+
const id = entry?.workflowId ?? workflowId;
|
|
92239
|
+
if (entry !== undefined || isFullRunId(workflowId))
|
|
92240
|
+
await backend.hydrateWorkflow(id);
|
|
92241
|
+
const handle = backend.getWorkflow(id);
|
|
91974
92242
|
return await openCompletedDurableWorkflow(workflowId, {
|
|
91975
92243
|
durableBackend: backend,
|
|
91976
92244
|
store: deps.store,
|
|
@@ -92227,19 +92495,19 @@ function createExtensionRuntime(opts = {}) {
|
|
|
92227
92495
|
}
|
|
92228
92496
|
|
|
92229
92497
|
// dist/builtin/workflows/src/extension/status-writer.ts
|
|
92230
|
-
import { mkdir as
|
|
92231
|
-
import { dirname as
|
|
92498
|
+
import { mkdir as mkdir8, rename as rename2, writeFile as writeFile11 } from "node:fs/promises";
|
|
92499
|
+
import { dirname as dirname16, join as join34 } from "node:path";
|
|
92232
92500
|
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME4 } from "@bastani/atomic";
|
|
92233
|
-
var DEFAULT_STATUS_SUBPATH =
|
|
92501
|
+
var DEFAULT_STATUS_SUBPATH = join34(CONFIG_DIR_NAME4, "workflows", "status.json");
|
|
92234
92502
|
function resolveStatusFilePath(config, opts = {}) {
|
|
92235
92503
|
if (config.statusFilePath)
|
|
92236
92504
|
return config.statusFilePath;
|
|
92237
92505
|
const root = opts.projectRoot ?? process.cwd();
|
|
92238
|
-
return
|
|
92506
|
+
return join34(root, DEFAULT_STATUS_SUBPATH);
|
|
92239
92507
|
}
|
|
92240
92508
|
async function atomicWriteJson(path, content) {
|
|
92241
|
-
const dir =
|
|
92242
|
-
await
|
|
92509
|
+
const dir = dirname16(path);
|
|
92510
|
+
await mkdir8(dir, { recursive: true });
|
|
92243
92511
|
const tmpPath = `${path}.tmp`;
|
|
92244
92512
|
await writeFile11(tmpPath, content, "utf8");
|
|
92245
92513
|
await rename2(tmpPath, path);
|
|
@@ -92524,7 +92792,7 @@ function createWorkflowHeartbeatDelivery(options) {
|
|
|
92524
92792
|
}
|
|
92525
92793
|
|
|
92526
92794
|
// dist/builtin/workflows/src/extension/workflow-heartbeat-scheduler.ts
|
|
92527
|
-
var
|
|
92795
|
+
var MAX_TIMER_DELAY_MS2 = 2147483647;
|
|
92528
92796
|
var MS_PER_MINUTE = 60000;
|
|
92529
92797
|
function createWorkflowHeartbeatSchedulerState() {
|
|
92530
92798
|
return {
|
|
@@ -92753,7 +93021,7 @@ function installWorkflowHeartbeatScheduler(options) {
|
|
|
92753
93021
|
if (next === undefined)
|
|
92754
93022
|
return;
|
|
92755
93023
|
const nextAt = next.scheduledAt;
|
|
92756
|
-
const delay = Math.min(Math.max(1, Math.ceil(nextAt - now())),
|
|
93024
|
+
const delay = Math.min(Math.max(1, Math.ceil(nextAt - now())), MAX_TIMER_DELAY_MS2);
|
|
92757
93025
|
const handle = timers.setTimeout(() => {
|
|
92758
93026
|
timerHandle = undefined;
|
|
92759
93027
|
processDue();
|
|
@@ -93410,6 +93678,11 @@ function createWorkflowExtensionRuntimeState(pi, adapters, options = {}) {
|
|
|
93410
93678
|
return targeted.call(runtimeRef.current, workflowIds);
|
|
93411
93679
|
return runtimeRef.current.prepareDurableResumable();
|
|
93412
93680
|
},
|
|
93681
|
+
get prepareDurableCatalog() {
|
|
93682
|
+
const runtime = runtimeRef.current;
|
|
93683
|
+
const catalog = runtime.prepareDurableCatalog;
|
|
93684
|
+
return catalog === undefined ? undefined : () => catalog.call(runtime);
|
|
93685
|
+
},
|
|
93413
93686
|
prepareCompletedDurable() {
|
|
93414
93687
|
return runtimeRef.current.prepareCompletedDurable?.() ?? Promise.resolve([]);
|
|
93415
93688
|
},
|