la-machina-engine 0.19.2 → 0.19.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +248 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +116 -62
- package/dist/index.d.ts +116 -62
- package/dist/index.js +248 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1649,7 +1649,13 @@ function deepMerge(base, override) {
|
|
|
1649
1649
|
}
|
|
1650
1650
|
return result;
|
|
1651
1651
|
}
|
|
1652
|
-
var API_RUNTIME_KEYS = [
|
|
1652
|
+
var API_RUNTIME_KEYS = [
|
|
1653
|
+
"env",
|
|
1654
|
+
"resolveAuth",
|
|
1655
|
+
"resolveBaseUrl",
|
|
1656
|
+
"onRequest",
|
|
1657
|
+
"onResponse"
|
|
1658
|
+
];
|
|
1653
1659
|
function splitApiRuntime(user) {
|
|
1654
1660
|
const api = user.api;
|
|
1655
1661
|
if (api === void 0) return { stripped: user, runtime: {} };
|
|
@@ -10974,6 +10980,38 @@ var RunStateManager = class {
|
|
|
10974
10980
|
await this.write(next);
|
|
10975
10981
|
return next;
|
|
10976
10982
|
}
|
|
10983
|
+
/**
|
|
10984
|
+
* Merge async lifecycle timing fields into the durable state.
|
|
10985
|
+
* Existing timestamps are preserved unless explicitly overwritten
|
|
10986
|
+
* by the caller.
|
|
10987
|
+
*/
|
|
10988
|
+
async patchAsyncTiming(runId, nodeId, patch) {
|
|
10989
|
+
const current = await this.read(runId, nodeId);
|
|
10990
|
+
if (current === null) {
|
|
10991
|
+
throw new Error(`RunStateManager.patchAsyncTiming: no state found for ${runId}/${nodeId}`);
|
|
10992
|
+
}
|
|
10993
|
+
const next = {
|
|
10994
|
+
...current,
|
|
10995
|
+
asyncTiming: { ...current.asyncTiming ?? {}, ...patch }
|
|
10996
|
+
};
|
|
10997
|
+
await this.write(next);
|
|
10998
|
+
return next;
|
|
10999
|
+
}
|
|
11000
|
+
async appendManualWebhookRetry(runId, nodeId, row) {
|
|
11001
|
+
const current = await this.read(runId, nodeId);
|
|
11002
|
+
if (current === null) {
|
|
11003
|
+
throw new Error(
|
|
11004
|
+
`RunStateManager.appendManualWebhookRetry: no state found for ${runId}/${nodeId}`
|
|
11005
|
+
);
|
|
11006
|
+
}
|
|
11007
|
+
const retries = current.manualWebhookRetries ?? [];
|
|
11008
|
+
const next = {
|
|
11009
|
+
...current,
|
|
11010
|
+
manualWebhookRetries: [...retries, row]
|
|
11011
|
+
};
|
|
11012
|
+
await this.write(next);
|
|
11013
|
+
return next;
|
|
11014
|
+
}
|
|
10977
11015
|
/**
|
|
10978
11016
|
* Update just the heartbeat + progress (cheap, called every turn).
|
|
10979
11017
|
*/
|
|
@@ -11710,6 +11748,7 @@ ${inputJson}
|
|
|
11710
11748
|
* uses fire-and-forget Promises which won't survive Worker request exit.
|
|
11711
11749
|
*/
|
|
11712
11750
|
async start(options) {
|
|
11751
|
+
const startCalledAt = Date.now();
|
|
11713
11752
|
const runId = options.runId ?? `run_${randomUUID()}`;
|
|
11714
11753
|
const storage = await this.buildStorage();
|
|
11715
11754
|
const stateManager = new RunStateManager(storage.workspace);
|
|
@@ -11721,19 +11760,62 @@ ${inputJson}
|
|
|
11721
11760
|
deliveries: []
|
|
11722
11761
|
} : void 0;
|
|
11723
11762
|
const initial = RunStateManager.initial(runId, options.nodeId, webhook);
|
|
11724
|
-
await stateManager.write(
|
|
11763
|
+
await stateManager.write({
|
|
11764
|
+
...initial,
|
|
11765
|
+
asyncTiming: { startCalledAt }
|
|
11766
|
+
});
|
|
11767
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11768
|
+
initialStateWrittenAt: Date.now()
|
|
11769
|
+
});
|
|
11725
11770
|
const handoffEnabled = this.config.runner !== void 0;
|
|
11771
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11772
|
+
backgroundScheduledAt: Date.now()
|
|
11773
|
+
});
|
|
11726
11774
|
this.backgroundExecutor.schedule(runId, async (signal) => {
|
|
11775
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11776
|
+
backgroundStartedAt: Date.now()
|
|
11777
|
+
});
|
|
11778
|
+
if (signal.aborted) return;
|
|
11727
11779
|
await stateManager.update(runId, options.nodeId, { status: "running" });
|
|
11728
11780
|
try {
|
|
11781
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11782
|
+
runCallStartedAt: Date.now()
|
|
11783
|
+
});
|
|
11729
11784
|
const response = await this.run({ ...options, runId }, { handoffToRunner: handoffEnabled });
|
|
11785
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11786
|
+
runCallCompletedAt: Date.now()
|
|
11787
|
+
});
|
|
11730
11788
|
if (signal.aborted) return;
|
|
11789
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11790
|
+
handoffStartedAt: Date.now()
|
|
11791
|
+
});
|
|
11731
11792
|
const postHandoff = await this.maybeHandoffToRunner(runId, options.nodeId, response);
|
|
11793
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11794
|
+
handoffCompletedAt: Date.now(),
|
|
11795
|
+
finalizeStartedAt: Date.now()
|
|
11796
|
+
});
|
|
11797
|
+
if (await this.runnerAlreadyWroteTerminal(stateManager, runId, options.nodeId, postHandoff)) {
|
|
11798
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11799
|
+
finalizeCompletedAt: Date.now(),
|
|
11800
|
+
backgroundCompletedAt: Date.now()
|
|
11801
|
+
});
|
|
11802
|
+
return;
|
|
11803
|
+
}
|
|
11732
11804
|
await stateManager.finalize(runId, options.nodeId, postHandoff);
|
|
11805
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11806
|
+
finalizeCompletedAt: Date.now()
|
|
11807
|
+
});
|
|
11733
11808
|
await this.maybeFireWebhook(stateManager, runId, options.nodeId, postHandoff);
|
|
11809
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11810
|
+
backgroundCompletedAt: Date.now()
|
|
11811
|
+
});
|
|
11734
11812
|
} catch (err) {
|
|
11735
11813
|
if (signal.aborted) return;
|
|
11736
11814
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
11815
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11816
|
+
backgroundFailedAt: Date.now(),
|
|
11817
|
+
errorMessage: errorMsg
|
|
11818
|
+
});
|
|
11737
11819
|
const failResponse = {
|
|
11738
11820
|
runId,
|
|
11739
11821
|
status: "failed",
|
|
@@ -11742,8 +11824,17 @@ ${inputJson}
|
|
|
11742
11824
|
errors: [{ code: "RUN_FAILED", message: errorMsg }],
|
|
11743
11825
|
timestamp: Date.now()
|
|
11744
11826
|
};
|
|
11827
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11828
|
+
finalizeStartedAt: Date.now()
|
|
11829
|
+
});
|
|
11745
11830
|
await stateManager.finalize(runId, options.nodeId, failResponse);
|
|
11831
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11832
|
+
finalizeCompletedAt: Date.now()
|
|
11833
|
+
});
|
|
11746
11834
|
await this.maybeFireWebhook(stateManager, runId, options.nodeId, failResponse);
|
|
11835
|
+
await this.recordAsyncTiming(stateManager, runId, options.nodeId, {
|
|
11836
|
+
backgroundCompletedAt: Date.now()
|
|
11837
|
+
});
|
|
11747
11838
|
}
|
|
11748
11839
|
});
|
|
11749
11840
|
return { runId, nodeId: options.nodeId, status: "queued" };
|
|
@@ -11753,6 +11844,7 @@ ${inputJson}
|
|
|
11753
11844
|
* dispatched via the background executor. Returns immediately.
|
|
11754
11845
|
*/
|
|
11755
11846
|
async resumeAsync(options) {
|
|
11847
|
+
const startCalledAt = Date.now();
|
|
11756
11848
|
const storage = await this.buildStorage();
|
|
11757
11849
|
const stateManager = new RunStateManager(storage.workspace);
|
|
11758
11850
|
let nodeId = options.nodeId;
|
|
@@ -11774,21 +11866,74 @@ ${inputJson}
|
|
|
11774
11866
|
lastHeartbeat: Date.now(),
|
|
11775
11867
|
response: null,
|
|
11776
11868
|
// clear stale paused response so getStatus returns provisional
|
|
11869
|
+
asyncTiming: {
|
|
11870
|
+
...existing.asyncTiming ?? {},
|
|
11871
|
+
startCalledAt
|
|
11872
|
+
},
|
|
11777
11873
|
...webhook !== void 0 ? { webhook } : {}
|
|
11778
|
-
} : {
|
|
11874
|
+
} : {
|
|
11875
|
+
...RunStateManager.initial(options.runId, nodeId, webhook),
|
|
11876
|
+
status: "running",
|
|
11877
|
+
asyncTiming: { startCalledAt }
|
|
11878
|
+
};
|
|
11779
11879
|
await stateManager.write(next);
|
|
11880
|
+
await this.recordAsyncTiming(stateManager, options.runId, nodeId, {
|
|
11881
|
+
initialStateWrittenAt: Date.now()
|
|
11882
|
+
});
|
|
11780
11883
|
const resumeNodeId = nodeId;
|
|
11781
11884
|
const handoffEnabled = this.config.runner !== void 0;
|
|
11885
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11886
|
+
backgroundScheduledAt: Date.now()
|
|
11887
|
+
});
|
|
11782
11888
|
this.backgroundExecutor.schedule(options.runId, async (signal) => {
|
|
11889
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11890
|
+
backgroundStartedAt: Date.now()
|
|
11891
|
+
});
|
|
11892
|
+
if (signal.aborted) return;
|
|
11783
11893
|
try {
|
|
11894
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11895
|
+
runCallStartedAt: Date.now()
|
|
11896
|
+
});
|
|
11784
11897
|
const response = await this.resume(options, { handoffToRunner: handoffEnabled });
|
|
11898
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11899
|
+
runCallCompletedAt: Date.now()
|
|
11900
|
+
});
|
|
11785
11901
|
if (signal.aborted) return;
|
|
11902
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11903
|
+
handoffStartedAt: Date.now()
|
|
11904
|
+
});
|
|
11786
11905
|
const postHandoff = await this.maybeHandoffToRunner(options.runId, resumeNodeId, response);
|
|
11906
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11907
|
+
handoffCompletedAt: Date.now(),
|
|
11908
|
+
finalizeStartedAt: Date.now()
|
|
11909
|
+
});
|
|
11910
|
+
if (await this.runnerAlreadyWroteTerminal(
|
|
11911
|
+
stateManager,
|
|
11912
|
+
options.runId,
|
|
11913
|
+
resumeNodeId,
|
|
11914
|
+
postHandoff
|
|
11915
|
+
)) {
|
|
11916
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11917
|
+
finalizeCompletedAt: Date.now(),
|
|
11918
|
+
backgroundCompletedAt: Date.now()
|
|
11919
|
+
});
|
|
11920
|
+
return;
|
|
11921
|
+
}
|
|
11787
11922
|
await stateManager.finalize(options.runId, resumeNodeId, postHandoff);
|
|
11923
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11924
|
+
finalizeCompletedAt: Date.now()
|
|
11925
|
+
});
|
|
11788
11926
|
await this.maybeFireWebhook(stateManager, options.runId, resumeNodeId, postHandoff);
|
|
11927
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11928
|
+
backgroundCompletedAt: Date.now()
|
|
11929
|
+
});
|
|
11789
11930
|
} catch (err) {
|
|
11790
11931
|
if (signal.aborted) return;
|
|
11791
11932
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
11933
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11934
|
+
backgroundFailedAt: Date.now(),
|
|
11935
|
+
errorMessage: errorMsg
|
|
11936
|
+
});
|
|
11792
11937
|
const failResponse = {
|
|
11793
11938
|
runId: options.runId,
|
|
11794
11939
|
status: "failed",
|
|
@@ -11797,8 +11942,17 @@ ${inputJson}
|
|
|
11797
11942
|
errors: [{ code: "RESUME_FAILED", message: errorMsg }],
|
|
11798
11943
|
timestamp: Date.now()
|
|
11799
11944
|
};
|
|
11945
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11946
|
+
finalizeStartedAt: Date.now()
|
|
11947
|
+
});
|
|
11800
11948
|
await stateManager.finalize(options.runId, resumeNodeId, failResponse);
|
|
11949
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11950
|
+
finalizeCompletedAt: Date.now()
|
|
11951
|
+
});
|
|
11801
11952
|
await this.maybeFireWebhook(stateManager, options.runId, resumeNodeId, failResponse);
|
|
11953
|
+
await this.recordAsyncTiming(stateManager, options.runId, resumeNodeId, {
|
|
11954
|
+
backgroundCompletedAt: Date.now()
|
|
11955
|
+
});
|
|
11802
11956
|
}
|
|
11803
11957
|
});
|
|
11804
11958
|
return { runId: options.runId, nodeId, status: "running" };
|
|
@@ -11831,7 +11985,15 @@ ${inputJson}
|
|
|
11831
11985
|
timestamp: Date.now()
|
|
11832
11986
|
};
|
|
11833
11987
|
}
|
|
11834
|
-
if (state.response !== null)
|
|
11988
|
+
if (state.response !== null) {
|
|
11989
|
+
return state.asyncTiming === void 0 ? state.response : {
|
|
11990
|
+
...state.response,
|
|
11991
|
+
meta: {
|
|
11992
|
+
...state.response.meta,
|
|
11993
|
+
asyncTiming: state.asyncTiming
|
|
11994
|
+
}
|
|
11995
|
+
};
|
|
11996
|
+
}
|
|
11835
11997
|
return {
|
|
11836
11998
|
runId: state.runId,
|
|
11837
11999
|
status: state.status,
|
|
@@ -11841,7 +12003,8 @@ ${inputJson}
|
|
|
11841
12003
|
turns: state.progress.turns,
|
|
11842
12004
|
tokensUsed: state.progress.tokensUsed,
|
|
11843
12005
|
activity: state.progress.currentActivity,
|
|
11844
|
-
...state.progress.lastTool !== void 0 ? { lastTool: state.progress.lastTool } : {}
|
|
12006
|
+
...state.progress.lastTool !== void 0 ? { lastTool: state.progress.lastTool } : {},
|
|
12007
|
+
...state.asyncTiming !== void 0 ? { asyncTiming: state.asyncTiming } : {}
|
|
11845
12008
|
},
|
|
11846
12009
|
errors: [],
|
|
11847
12010
|
timestamp: state.lastHeartbeat
|
|
@@ -11850,6 +12013,11 @@ ${inputJson}
|
|
|
11850
12013
|
/**
|
|
11851
12014
|
* Poll until the run reaches a terminal state (done | failed | paused |
|
|
11852
12015
|
* cancelled) or the timeout expires. Returns the final EngineResponse.
|
|
12016
|
+
*
|
|
12017
|
+
* For async paused runs, wait until the background wrapper has completed
|
|
12018
|
+
* its post-finalize bookkeeping before returning. Otherwise a caller can
|
|
12019
|
+
* immediately resume while the previous wrapper is still writing timing
|
|
12020
|
+
* diagnostics, allowing a stale paused state to overwrite the resumed run.
|
|
11853
12021
|
*/
|
|
11854
12022
|
async waitFor(runId, opts = {}) {
|
|
11855
12023
|
const pollInterval = opts.pollIntervalMs ?? 1e3;
|
|
@@ -11857,9 +12025,10 @@ ${inputJson}
|
|
|
11857
12025
|
const deadline = timeoutMs > 0 ? Date.now() + timeoutMs : Infinity;
|
|
11858
12026
|
for (; ; ) {
|
|
11859
12027
|
const resp = await this.getStatus(runId, opts.nodeId);
|
|
11860
|
-
if (resp.status === "done" || resp.status === "failed"
|
|
12028
|
+
if (resp.status === "done" || resp.status === "failed") {
|
|
11861
12029
|
return resp;
|
|
11862
12030
|
}
|
|
12031
|
+
if (resp.status === "paused" && this.pausedRunIsQuiesced(resp, opts)) return resp;
|
|
11863
12032
|
if (Date.now() >= deadline) {
|
|
11864
12033
|
return {
|
|
11865
12034
|
runId,
|
|
@@ -11875,6 +12044,12 @@ ${inputJson}
|
|
|
11875
12044
|
await new Promise((r) => setTimeout(r, pollInterval));
|
|
11876
12045
|
}
|
|
11877
12046
|
}
|
|
12047
|
+
pausedRunIsQuiesced(resp, opts) {
|
|
12048
|
+
if (resp.meta.pauseReason === "handoff_to_runner") return opts.waitForRunnerHandoff !== true;
|
|
12049
|
+
const timing = resp.meta.asyncTiming;
|
|
12050
|
+
if (timing === void 0) return true;
|
|
12051
|
+
return timing.backgroundCompletedAt !== void 0 || timing.backgroundFailedAt !== void 0;
|
|
12052
|
+
}
|
|
11878
12053
|
/**
|
|
11879
12054
|
* Cancel an async run. Aborts the background executor and marks the
|
|
11880
12055
|
* state as cancelled. Idempotent — safe to call on already-terminal runs.
|
|
@@ -11931,14 +12106,31 @@ ${inputJson}
|
|
|
11931
12106
|
if (original === void 0) {
|
|
11932
12107
|
throw new Error(`retryWebhook: delivery ${deliveryId} not found`);
|
|
11933
12108
|
}
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11941
|
-
|
|
12109
|
+
const retryStartedAt = Date.now();
|
|
12110
|
+
try {
|
|
12111
|
+
await this.dispatchWebhookWithRetries(
|
|
12112
|
+
stateManager,
|
|
12113
|
+
runId,
|
|
12114
|
+
targetNodeId,
|
|
12115
|
+
original.event,
|
|
12116
|
+
state.response,
|
|
12117
|
+
1
|
|
12118
|
+
);
|
|
12119
|
+
await this.recordManualWebhookRetry(stateManager, runId, targetNodeId, {
|
|
12120
|
+
deliveryId,
|
|
12121
|
+
startedAt: retryStartedAt,
|
|
12122
|
+
completedAt: Date.now()
|
|
12123
|
+
});
|
|
12124
|
+
} catch (err) {
|
|
12125
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
12126
|
+
await this.recordManualWebhookRetry(stateManager, runId, targetNodeId, {
|
|
12127
|
+
deliveryId,
|
|
12128
|
+
startedAt: retryStartedAt,
|
|
12129
|
+
completedAt: Date.now(),
|
|
12130
|
+
errorMessage
|
|
12131
|
+
});
|
|
12132
|
+
throw err;
|
|
12133
|
+
}
|
|
11942
12134
|
}
|
|
11943
12135
|
/**
|
|
11944
12136
|
* Scan all runs for stale heartbeats and mark them as failed. Clients
|
|
@@ -11975,6 +12167,12 @@ ${inputJson}
|
|
|
11975
12167
|
return orphaned;
|
|
11976
12168
|
}
|
|
11977
12169
|
// ---------- runner handoff (Plan 019) ----------
|
|
12170
|
+
async runnerAlreadyWroteTerminal(stateManager, runId, nodeId, response) {
|
|
12171
|
+
if (response.status !== "paused") return false;
|
|
12172
|
+
if (response.meta.pauseReason !== "handoff_to_runner") return false;
|
|
12173
|
+
const latest = await stateManager.read(runId, nodeId);
|
|
12174
|
+
return latest?.status === "done" || latest?.status === "failed" || latest?.status === "cancelled";
|
|
12175
|
+
}
|
|
11978
12176
|
/**
|
|
11979
12177
|
* When the response indicates the run paused for runner handoff, POST
|
|
11980
12178
|
* `{ runId }` to the configured runner URL. On success, return the
|
|
@@ -12040,7 +12238,22 @@ ${inputJson}
|
|
|
12040
12238
|
}
|
|
12041
12239
|
}
|
|
12042
12240
|
// ---------- webhook helpers ----------
|
|
12241
|
+
async recordAsyncTiming(stateManager, runId, nodeId, patch) {
|
|
12242
|
+
try {
|
|
12243
|
+
await stateManager.patchAsyncTiming(runId, nodeId, patch);
|
|
12244
|
+
} catch {
|
|
12245
|
+
}
|
|
12246
|
+
}
|
|
12247
|
+
async recordManualWebhookRetry(stateManager, runId, nodeId, row) {
|
|
12248
|
+
try {
|
|
12249
|
+
await stateManager.appendManualWebhookRetry(runId, nodeId, row);
|
|
12250
|
+
} catch {
|
|
12251
|
+
}
|
|
12252
|
+
}
|
|
12043
12253
|
async maybeFireWebhook(stateManager, runId, nodeId, response) {
|
|
12254
|
+
await this.recordAsyncTiming(stateManager, runId, nodeId, {
|
|
12255
|
+
webhookCheckStartedAt: Date.now()
|
|
12256
|
+
});
|
|
12044
12257
|
const state = await stateManager.read(runId, nodeId);
|
|
12045
12258
|
if (state === null || state.webhook === void 0) return;
|
|
12046
12259
|
const event = response.status === "done" ? "done" : response.status === "paused" ? "paused" : "failed";
|
|
@@ -12051,12 +12264,18 @@ ${inputJson}
|
|
|
12051
12264
|
const state = await stateManager.read(runId, nodeId);
|
|
12052
12265
|
if (state === null || state.webhook === void 0) return;
|
|
12053
12266
|
const hook = state.webhook;
|
|
12267
|
+
await this.recordAsyncTiming(stateManager, runId, nodeId, {
|
|
12268
|
+
webhookDispatchStartedAt: Date.now()
|
|
12269
|
+
});
|
|
12054
12270
|
let attempt = startAttempt;
|
|
12055
12271
|
while (attempt <= MAX_ATTEMPTS) {
|
|
12056
12272
|
const delay = RETRY_DELAYS_MS[attempt - 1] ?? 0;
|
|
12057
12273
|
if (delay > 0) {
|
|
12058
12274
|
await new Promise((r) => setTimeout(r, delay));
|
|
12059
12275
|
}
|
|
12276
|
+
await this.recordAsyncTiming(stateManager, runId, nodeId, {
|
|
12277
|
+
webhookHttpStartedAt: Date.now()
|
|
12278
|
+
});
|
|
12060
12279
|
const result = await this.webhookDispatcher.deliver({
|
|
12061
12280
|
url: hook.url,
|
|
12062
12281
|
event,
|
|
@@ -12065,6 +12284,9 @@ ${inputJson}
|
|
|
12065
12284
|
...hook.headers !== void 0 ? { headers: hook.headers } : {},
|
|
12066
12285
|
attempt
|
|
12067
12286
|
});
|
|
12287
|
+
await this.recordAsyncTiming(stateManager, runId, nodeId, {
|
|
12288
|
+
webhookHttpCompletedAt: Date.now()
|
|
12289
|
+
});
|
|
12068
12290
|
const latest = await stateManager.read(runId, nodeId);
|
|
12069
12291
|
if (latest !== null && latest.webhook !== void 0) {
|
|
12070
12292
|
const updated = {
|
|
@@ -12072,10 +12294,21 @@ ${inputJson}
|
|
|
12072
12294
|
deliveries: [...latest.webhook.deliveries, result.delivery]
|
|
12073
12295
|
};
|
|
12074
12296
|
await stateManager.update(runId, nodeId, { webhook: updated });
|
|
12297
|
+
await this.recordAsyncTiming(stateManager, runId, nodeId, {
|
|
12298
|
+
webhookStatePersistedAt: Date.now()
|
|
12299
|
+
});
|
|
12300
|
+
}
|
|
12301
|
+
if (!result.shouldRetry) {
|
|
12302
|
+
await this.recordAsyncTiming(stateManager, runId, nodeId, {
|
|
12303
|
+
webhookDispatchCompletedAt: Date.now()
|
|
12304
|
+
});
|
|
12305
|
+
return;
|
|
12075
12306
|
}
|
|
12076
|
-
if (!result.shouldRetry) return;
|
|
12077
12307
|
attempt += 1;
|
|
12078
12308
|
}
|
|
12309
|
+
await this.recordAsyncTiming(stateManager, runId, nodeId, {
|
|
12310
|
+
webhookDispatchCompletedAt: Date.now()
|
|
12311
|
+
});
|
|
12079
12312
|
}
|
|
12080
12313
|
/**
|
|
12081
12314
|
* Shut down engine-owned background resources — currently just the
|