@bratsos/workflow-engine 0.5.1 → 0.7.0
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/README.md +65 -12
- package/dist/{chunk-RZY5YRGL.js → chunk-2HEV5ZJL.js} +2 -2
- package/dist/chunk-2HEV5ZJL.js.map +1 -0
- package/dist/{chunk-WQPZ6KON.js → chunk-5C7LRNM7.js} +280 -93
- package/dist/chunk-5C7LRNM7.js.map +1 -0
- package/dist/{chunk-PHLNTR5Z.js → chunk-Q2XDO3UF.js} +28 -7
- package/dist/chunk-Q2XDO3UF.js.map +1 -0
- package/dist/{chunk-ZYMT2PAO.js → chunk-WWK2SPN7.js} +16 -37
- package/dist/chunk-WWK2SPN7.js.map +1 -0
- package/dist/{client-oLD5ilXp.d.ts → client-DYs5wlHp.d.ts} +17 -99
- package/dist/client.d.ts +4 -3
- package/dist/client.js +1 -1
- package/dist/events-D_P24UaY.d.ts +105 -0
- package/dist/{index-CVkkGnxx.d.ts → index-aNuJ2QgN.d.ts} +11 -1
- package/dist/index.d.ts +184 -32
- package/dist/index.js +41 -9
- package/dist/index.js.map +1 -1
- package/dist/{interface-TsryH4d7.d.ts → interface-BeEPzTFy.d.ts} +9 -3
- package/dist/kernel/index.d.ts +6 -5
- package/dist/kernel/index.js +2 -1
- package/dist/kernel/testing/index.d.ts +3 -2
- package/dist/persistence/index.d.ts +2 -2
- package/dist/persistence/index.js +2 -2
- package/dist/persistence/prisma/index.d.ts +2 -2
- package/dist/persistence/prisma/index.js +2 -2
- package/dist/{plugins-C94AT8Wr.d.ts → plugins-Cl0WVVrE.d.ts} +9 -6
- package/dist/{ports-855bktyD.d.ts → ports-swhiWFw4.d.ts} +5 -106
- package/dist/{stage-BPw7m9Wx.d.ts → stage-_7BKqqUG.d.ts} +2 -2
- package/dist/testing/index.d.ts +2 -1
- package/dist/testing/index.js +25 -6
- package/dist/testing/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/workflow-engine/SKILL.md +30 -11
- package/skills/workflow-engine/references/02-workflow-builder.md +2 -0
- package/skills/workflow-engine/references/03-runtime-setup.md +1 -1
- package/skills/workflow-engine/references/08-common-patterns.md +2 -1
- package/skills/workflow-engine/references/09-troubleshooting.md +4 -3
- package/dist/chunk-PHLNTR5Z.js.map +0 -1
- package/dist/chunk-RZY5YRGL.js.map +0 -1
- package/dist/chunk-WQPZ6KON.js.map +0 -1
- package/dist/chunk-ZYMT2PAO.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { StaleVersionError } from './chunk-2HEV5ZJL.js';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
|
|
3
|
-
// src/core/types.ts
|
|
4
4
|
z.object({
|
|
5
5
|
batchId: z.string(),
|
|
6
6
|
statusUrl: z.string().optional(),
|
|
@@ -78,15 +78,44 @@ function createStorageShim(workflowRunId, workflowType, deps) {
|
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
// src/kernel/helpers/resolve-execution-group-output.ts
|
|
82
|
+
function resolveExecutionGroupOutput(workflow, groupIndex, workflowContext) {
|
|
83
|
+
const stages = workflow.getStagesInExecutionGroup(groupIndex);
|
|
84
|
+
if (stages.length === 0) return void 0;
|
|
85
|
+
if (stages.length === 1) {
|
|
86
|
+
return workflowContext[stages[0].id];
|
|
87
|
+
}
|
|
88
|
+
const merged = {};
|
|
89
|
+
for (const stage of stages) {
|
|
90
|
+
if (workflowContext[stage.id] !== void 0) {
|
|
91
|
+
merged[stage.id] = workflowContext[stage.id];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return merged;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/kernel/helpers/save-stage-artifacts.ts
|
|
98
|
+
async function saveStageArtifacts(runId, workflowType, stageId, artifacts, deps) {
|
|
99
|
+
const artifactKeys = {};
|
|
100
|
+
for (const [artifactName, artifact] of Object.entries(artifacts)) {
|
|
101
|
+
const encodedName = encodeURIComponent(artifactName);
|
|
102
|
+
const key = `workflow-v2/${workflowType}/${runId}/${stageId}/artifacts/${encodedName}.json`;
|
|
103
|
+
await deps.blobStore.put(key, artifact);
|
|
104
|
+
artifactKeys[artifactName] = key;
|
|
105
|
+
}
|
|
106
|
+
return artifactKeys;
|
|
107
|
+
}
|
|
108
|
+
|
|
81
109
|
// src/kernel/handlers/job-execute.ts
|
|
82
110
|
function resolveStageInput(workflow, stageId, workflowRun, workflowContext) {
|
|
83
111
|
const groupIndex = workflow.getExecutionGroupIndex(stageId);
|
|
84
|
-
if (groupIndex
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
112
|
+
if (groupIndex <= 1) return workflowRun.input;
|
|
113
|
+
const prevOutput = resolveExecutionGroupOutput(
|
|
114
|
+
workflow,
|
|
115
|
+
groupIndex - 1,
|
|
116
|
+
workflowContext
|
|
117
|
+
);
|
|
118
|
+
return prevOutput ?? workflowRun.input;
|
|
90
119
|
}
|
|
91
120
|
function toOutboxEvents(workflowRunId, causationId, events) {
|
|
92
121
|
return events.map((event) => ({
|
|
@@ -112,6 +141,7 @@ async function handleJobExecute(command, deps) {
|
|
|
112
141
|
if (workflowRun.status !== "RUNNING") {
|
|
113
142
|
return {
|
|
114
143
|
outcome: "failed",
|
|
144
|
+
ghost: true,
|
|
115
145
|
error: `Run ${workflowRunId} is ${workflowRun.status}, expected RUNNING \u2014 ghost job discarded`,
|
|
116
146
|
_events: []
|
|
117
147
|
};
|
|
@@ -202,6 +232,15 @@ async function handleJobExecute(command, deps) {
|
|
|
202
232
|
workflowContext
|
|
203
233
|
};
|
|
204
234
|
const result = await stageDef.execute(context);
|
|
235
|
+
const currentRunStatus = await deps.persistence.getRunStatus(workflowRunId);
|
|
236
|
+
if (currentRunStatus !== "RUNNING") {
|
|
237
|
+
return {
|
|
238
|
+
outcome: "failed",
|
|
239
|
+
ghost: true,
|
|
240
|
+
error: `Run ${workflowRunId} was ${currentRunStatus} after stage execution \u2014 result discarded`,
|
|
241
|
+
_events: []
|
|
242
|
+
};
|
|
243
|
+
}
|
|
205
244
|
if (isSuspendedResult(result)) {
|
|
206
245
|
const { state, pollConfig, metrics } = result;
|
|
207
246
|
const nextPollAt = new Date(
|
|
@@ -241,12 +280,22 @@ async function handleJobExecute(command, deps) {
|
|
|
241
280
|
result.output,
|
|
242
281
|
deps
|
|
243
282
|
);
|
|
283
|
+
const artifactKeys = result.artifacts && Object.keys(result.artifacts).length > 0 ? await saveStageArtifacts(
|
|
284
|
+
workflowRunId,
|
|
285
|
+
workflowRun.workflowType,
|
|
286
|
+
stageId,
|
|
287
|
+
result.artifacts,
|
|
288
|
+
deps
|
|
289
|
+
) : void 0;
|
|
244
290
|
await deps.persistence.withTransaction(async (tx) => {
|
|
245
291
|
await tx.updateStage(stageRecord.id, {
|
|
246
292
|
status: "COMPLETED",
|
|
247
293
|
completedAt: deps.clock.now(),
|
|
248
294
|
duration,
|
|
249
|
-
outputData: {
|
|
295
|
+
outputData: {
|
|
296
|
+
_artifactKey: outputKey,
|
|
297
|
+
...artifactKeys ? { _artifactKeys: artifactKeys } : {}
|
|
298
|
+
},
|
|
250
299
|
metrics: result.metrics,
|
|
251
300
|
embeddingInfo: result.embeddings
|
|
252
301
|
});
|
|
@@ -362,6 +411,17 @@ async function handleRunCancel(command, deps) {
|
|
|
362
411
|
status: "CANCELLED",
|
|
363
412
|
completedAt: deps.clock.now()
|
|
364
413
|
});
|
|
414
|
+
const stages = await deps.persistence.getStagesByRun(command.workflowRunId);
|
|
415
|
+
for (const stage of stages) {
|
|
416
|
+
if (!TERMINAL_STATUSES.has(stage.status)) {
|
|
417
|
+
await deps.persistence.updateStage(stage.id, {
|
|
418
|
+
status: "CANCELLED",
|
|
419
|
+
completedAt: deps.clock.now(),
|
|
420
|
+
nextPollAt: null
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
await deps.jobTransport.cancelByRun(command.workflowRunId);
|
|
365
425
|
return {
|
|
366
426
|
cancelled: true,
|
|
367
427
|
_events: [
|
|
@@ -644,9 +704,10 @@ async function handleRunRerunFrom(command, deps) {
|
|
|
644
704
|
);
|
|
645
705
|
const deletedStageIds = stagesToDelete.map((s) => s.stageId);
|
|
646
706
|
for (const stage of stagesToDelete) {
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
707
|
+
const prefix = `workflow-v2/${run.workflowType}/${workflowRunId}/${stage.stageId}/`;
|
|
708
|
+
const keys = await deps.blobStore.list(prefix).catch(() => []);
|
|
709
|
+
for (const key of keys) {
|
|
710
|
+
await deps.blobStore.delete(key).catch(() => {
|
|
650
711
|
});
|
|
651
712
|
}
|
|
652
713
|
}
|
|
@@ -655,7 +716,12 @@ async function handleRunRerunFrom(command, deps) {
|
|
|
655
716
|
}
|
|
656
717
|
await deps.persistence.updateRun(workflowRunId, {
|
|
657
718
|
status: "RUNNING",
|
|
658
|
-
|
|
719
|
+
startedAt: deps.clock.now(),
|
|
720
|
+
completedAt: null,
|
|
721
|
+
duration: null,
|
|
722
|
+
output: null,
|
|
723
|
+
totalCost: 0,
|
|
724
|
+
totalTokens: 0
|
|
659
725
|
});
|
|
660
726
|
const targetStages = workflow.getStagesInExecutionGroup(targetGroup);
|
|
661
727
|
for (const stage of targetStages) {
|
|
@@ -694,6 +760,19 @@ async function handleRunRerunFrom(command, deps) {
|
|
|
694
760
|
// src/kernel/handlers/run-transition.ts
|
|
695
761
|
var TERMINAL_STATUSES2 = /* @__PURE__ */ new Set(["COMPLETED", "FAILED", "CANCELLED"]);
|
|
696
762
|
var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["RUNNING", "PENDING", "SUSPENDED"]);
|
|
763
|
+
async function claimRunTransition(run, deps) {
|
|
764
|
+
try {
|
|
765
|
+
await deps.persistence.updateRun(run.id, {
|
|
766
|
+
expectedVersion: run.version
|
|
767
|
+
});
|
|
768
|
+
return true;
|
|
769
|
+
} catch (error) {
|
|
770
|
+
if (error instanceof StaleVersionError) {
|
|
771
|
+
return false;
|
|
772
|
+
}
|
|
773
|
+
throw error;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
697
776
|
async function enqueueExecutionGroup(run, workflow, groupIndex, deps) {
|
|
698
777
|
const stages = workflow.getStagesInExecutionGroup(groupIndex);
|
|
699
778
|
const stagesToEnqueue = [];
|
|
@@ -742,6 +821,9 @@ async function handleRunTransition(command, deps) {
|
|
|
742
821
|
}
|
|
743
822
|
const stages = await deps.persistence.getStagesByRun(command.workflowRunId);
|
|
744
823
|
if (stages.length === 0) {
|
|
824
|
+
if (!await claimRunTransition(run, deps)) {
|
|
825
|
+
return { action: "noop", _events: [] };
|
|
826
|
+
}
|
|
745
827
|
await enqueueExecutionGroup(run, workflow, 1, deps);
|
|
746
828
|
events.push({
|
|
747
829
|
type: "workflow:started",
|
|
@@ -756,6 +838,9 @@ async function handleRunTransition(command, deps) {
|
|
|
756
838
|
}
|
|
757
839
|
const failedStage = stages.find((s) => s.status === "FAILED");
|
|
758
840
|
if (failedStage) {
|
|
841
|
+
if (!await claimRunTransition(run, deps)) {
|
|
842
|
+
return { action: "noop", _events: [] };
|
|
843
|
+
}
|
|
759
844
|
await deps.persistence.updateRun(command.workflowRunId, {
|
|
760
845
|
status: "FAILED",
|
|
761
846
|
completedAt: deps.clock.now()
|
|
@@ -774,6 +859,9 @@ async function handleRunTransition(command, deps) {
|
|
|
774
859
|
);
|
|
775
860
|
const nextGroupStages = workflow.getStagesInExecutionGroup(maxGroup + 1);
|
|
776
861
|
if (nextGroupStages.length > 0) {
|
|
862
|
+
if (!await claimRunTransition(run, deps)) {
|
|
863
|
+
return { action: "noop", _events: [] };
|
|
864
|
+
}
|
|
777
865
|
await enqueueExecutionGroup(run, workflow, maxGroup + 1, deps);
|
|
778
866
|
return {
|
|
779
867
|
action: "advanced",
|
|
@@ -791,10 +879,23 @@ async function handleRunTransition(command, deps) {
|
|
|
791
879
|
}
|
|
792
880
|
}
|
|
793
881
|
const duration = deps.clock.now().getTime() - run.createdAt.getTime();
|
|
882
|
+
const workflowContext = await loadWorkflowContext(
|
|
883
|
+
command.workflowRunId,
|
|
884
|
+
deps
|
|
885
|
+
);
|
|
886
|
+
const output = resolveExecutionGroupOutput(
|
|
887
|
+
workflow,
|
|
888
|
+
maxGroup,
|
|
889
|
+
workflowContext
|
|
890
|
+
);
|
|
891
|
+
if (!await claimRunTransition(run, deps)) {
|
|
892
|
+
return { action: "noop", _events: [] };
|
|
893
|
+
}
|
|
794
894
|
await deps.persistence.updateRun(command.workflowRunId, {
|
|
795
895
|
status: "COMPLETED",
|
|
796
896
|
completedAt: deps.clock.now(),
|
|
797
897
|
duration,
|
|
898
|
+
output,
|
|
798
899
|
totalCost,
|
|
799
900
|
totalTokens
|
|
800
901
|
});
|
|
@@ -803,6 +904,7 @@ async function handleRunTransition(command, deps) {
|
|
|
803
904
|
timestamp: deps.clock.now(),
|
|
804
905
|
workflowRunId: command.workflowRunId,
|
|
805
906
|
duration,
|
|
907
|
+
output,
|
|
806
908
|
totalCost,
|
|
807
909
|
totalTokens
|
|
808
910
|
});
|
|
@@ -820,6 +922,29 @@ function toOutboxEvents2(workflowRunId, events) {
|
|
|
820
922
|
occurredAt: event.timestamp
|
|
821
923
|
}));
|
|
822
924
|
}
|
|
925
|
+
async function markStageCancelled(stageId, deps) {
|
|
926
|
+
await deps.persistence.updateStage(stageId, {
|
|
927
|
+
status: "CANCELLED",
|
|
928
|
+
completedAt: deps.clock.now(),
|
|
929
|
+
nextPollAt: null
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
async function withClaimedRun(workflowRunId, expectedVersion, deps, fn) {
|
|
933
|
+
try {
|
|
934
|
+
const value = await deps.persistence.withTransaction(async (tx) => {
|
|
935
|
+
await tx.updateRun(workflowRunId, {
|
|
936
|
+
expectedVersion
|
|
937
|
+
});
|
|
938
|
+
return fn(tx);
|
|
939
|
+
});
|
|
940
|
+
return { status: "claimed", value };
|
|
941
|
+
} catch (error) {
|
|
942
|
+
if (error instanceof StaleVersionError) {
|
|
943
|
+
return { status: "stale" };
|
|
944
|
+
}
|
|
945
|
+
throw error;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
823
948
|
async function handleStagePollSuspended(command, deps) {
|
|
824
949
|
const maxChecks = command.maxChecks ?? 50;
|
|
825
950
|
const suspendedStages = await deps.persistence.getSuspendedStages(
|
|
@@ -834,6 +959,10 @@ async function handleStagePollSuspended(command, deps) {
|
|
|
834
959
|
checked++;
|
|
835
960
|
const run = await deps.persistence.getRun(stageRecord.workflowRunId);
|
|
836
961
|
if (!run) continue;
|
|
962
|
+
if (run.status === "CANCELLED") {
|
|
963
|
+
await markStageCancelled(stageRecord.id, deps);
|
|
964
|
+
continue;
|
|
965
|
+
}
|
|
837
966
|
const workflow = deps.registry.getWorkflow(run.workflowId);
|
|
838
967
|
if (!workflow) {
|
|
839
968
|
await deps.persistence.withTransaction(async (tx) => {
|
|
@@ -913,36 +1042,50 @@ async function handleStagePollSuspended(command, deps) {
|
|
|
913
1042
|
checkContext
|
|
914
1043
|
);
|
|
915
1044
|
if (checkResult.error) {
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
1045
|
+
const claimResult = await withClaimedRun(
|
|
1046
|
+
stageRecord.workflowRunId,
|
|
1047
|
+
run.version,
|
|
1048
|
+
deps,
|
|
1049
|
+
async (tx) => {
|
|
1050
|
+
await tx.updateStage(stageRecord.id, {
|
|
1051
|
+
status: "FAILED",
|
|
1052
|
+
completedAt: deps.clock.now(),
|
|
1053
|
+
errorMessage: checkResult.error,
|
|
1054
|
+
nextPollAt: null
|
|
1055
|
+
});
|
|
1056
|
+
await tx.updateRun(stageRecord.workflowRunId, {
|
|
1057
|
+
status: "FAILED",
|
|
1058
|
+
completedAt: deps.clock.now()
|
|
1059
|
+
});
|
|
1060
|
+
await tx.appendOutboxEvents(
|
|
1061
|
+
toOutboxEvents2(stageRecord.workflowRunId, [
|
|
1062
|
+
{
|
|
1063
|
+
type: "stage:failed",
|
|
1064
|
+
timestamp: deps.clock.now(),
|
|
1065
|
+
workflowRunId: stageRecord.workflowRunId,
|
|
1066
|
+
stageId: stageRecord.stageId,
|
|
1067
|
+
stageName: stageRecord.stageName,
|
|
1068
|
+
error: checkResult.error
|
|
1069
|
+
},
|
|
1070
|
+
{
|
|
1071
|
+
type: "workflow:failed",
|
|
1072
|
+
timestamp: deps.clock.now(),
|
|
1073
|
+
workflowRunId: stageRecord.workflowRunId,
|
|
1074
|
+
error: checkResult.error
|
|
1075
|
+
}
|
|
1076
|
+
])
|
|
1077
|
+
);
|
|
1078
|
+
}
|
|
1079
|
+
);
|
|
1080
|
+
if (claimResult.status === "stale") {
|
|
1081
|
+
const latestStatus = await deps.persistence.getRunStatus(
|
|
1082
|
+
stageRecord.workflowRunId
|
|
944
1083
|
);
|
|
945
|
-
|
|
1084
|
+
if (latestStatus === "CANCELLED") {
|
|
1085
|
+
await markStageCancelled(stageRecord.id, deps);
|
|
1086
|
+
}
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
946
1089
|
failed++;
|
|
947
1090
|
} else if (checkResult.ready) {
|
|
948
1091
|
let outputRef;
|
|
@@ -962,70 +1105,114 @@ async function handleStagePollSuspended(command, deps) {
|
|
|
962
1105
|
outputRef = { _artifactKey: outputKey };
|
|
963
1106
|
}
|
|
964
1107
|
const duration = deps.clock.now().getTime() - (stageRecord.startedAt?.getTime() ?? deps.clock.now().getTime());
|
|
965
|
-
|
|
1108
|
+
const claimResult = await withClaimedRun(
|
|
1109
|
+
stageRecord.workflowRunId,
|
|
1110
|
+
run.version,
|
|
1111
|
+
deps,
|
|
1112
|
+
async (tx) => {
|
|
1113
|
+
await tx.updateStage(stageRecord.id, {
|
|
1114
|
+
status: "COMPLETED",
|
|
1115
|
+
completedAt: deps.clock.now(),
|
|
1116
|
+
duration,
|
|
1117
|
+
outputData: outputRef,
|
|
1118
|
+
nextPollAt: null,
|
|
1119
|
+
metrics: checkResult.metrics,
|
|
1120
|
+
embeddingInfo: checkResult.embeddings
|
|
1121
|
+
});
|
|
1122
|
+
await tx.appendOutboxEvents(
|
|
1123
|
+
toOutboxEvents2(stageRecord.workflowRunId, [
|
|
1124
|
+
{
|
|
1125
|
+
type: "stage:completed",
|
|
1126
|
+
timestamp: deps.clock.now(),
|
|
1127
|
+
workflowRunId: stageRecord.workflowRunId,
|
|
1128
|
+
stageId: stageRecord.stageId,
|
|
1129
|
+
stageName: stageRecord.stageName,
|
|
1130
|
+
duration
|
|
1131
|
+
}
|
|
1132
|
+
])
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
);
|
|
1136
|
+
if (claimResult.status === "stale") {
|
|
1137
|
+
const latestStatus = await deps.persistence.getRunStatus(
|
|
1138
|
+
stageRecord.workflowRunId
|
|
1139
|
+
);
|
|
1140
|
+
if (latestStatus === "CANCELLED") {
|
|
1141
|
+
await markStageCancelled(stageRecord.id, deps);
|
|
1142
|
+
}
|
|
1143
|
+
continue;
|
|
1144
|
+
}
|
|
1145
|
+
resumed++;
|
|
1146
|
+
resumedWorkflowRunIds.add(stageRecord.workflowRunId);
|
|
1147
|
+
} else {
|
|
1148
|
+
const pollInterval = checkResult.nextCheckIn ?? stageRecord.pollInterval ?? 6e4;
|
|
1149
|
+
const nextPollAt = new Date(deps.clock.now().getTime() + pollInterval);
|
|
1150
|
+
const claimResult = await withClaimedRun(
|
|
1151
|
+
stageRecord.workflowRunId,
|
|
1152
|
+
run.version,
|
|
1153
|
+
deps,
|
|
1154
|
+
async (tx) => {
|
|
1155
|
+
await tx.updateStage(stageRecord.id, {
|
|
1156
|
+
nextPollAt
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
);
|
|
1160
|
+
if (claimResult.status === "stale") {
|
|
1161
|
+
const latestStatus = await deps.persistence.getRunStatus(
|
|
1162
|
+
stageRecord.workflowRunId
|
|
1163
|
+
);
|
|
1164
|
+
if (latestStatus === "CANCELLED") {
|
|
1165
|
+
await markStageCancelled(stageRecord.id, deps);
|
|
1166
|
+
}
|
|
1167
|
+
continue;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
} catch (error) {
|
|
1171
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1172
|
+
const claimResult = await withClaimedRun(
|
|
1173
|
+
stageRecord.workflowRunId,
|
|
1174
|
+
run.version,
|
|
1175
|
+
deps,
|
|
1176
|
+
async (tx) => {
|
|
966
1177
|
await tx.updateStage(stageRecord.id, {
|
|
967
|
-
status: "
|
|
1178
|
+
status: "FAILED",
|
|
968
1179
|
completedAt: deps.clock.now(),
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1180
|
+
errorMessage,
|
|
1181
|
+
nextPollAt: null
|
|
1182
|
+
});
|
|
1183
|
+
await tx.updateRun(stageRecord.workflowRunId, {
|
|
1184
|
+
status: "FAILED",
|
|
1185
|
+
completedAt: deps.clock.now()
|
|
974
1186
|
});
|
|
975
1187
|
await tx.appendOutboxEvents(
|
|
976
1188
|
toOutboxEvents2(stageRecord.workflowRunId, [
|
|
977
1189
|
{
|
|
978
|
-
type: "stage:
|
|
1190
|
+
type: "stage:failed",
|
|
979
1191
|
timestamp: deps.clock.now(),
|
|
980
1192
|
workflowRunId: stageRecord.workflowRunId,
|
|
981
1193
|
stageId: stageRecord.stageId,
|
|
982
1194
|
stageName: stageRecord.stageName,
|
|
983
|
-
|
|
1195
|
+
error: errorMessage
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
type: "workflow:failed",
|
|
1199
|
+
timestamp: deps.clock.now(),
|
|
1200
|
+
workflowRunId: stageRecord.workflowRunId,
|
|
1201
|
+
error: errorMessage
|
|
984
1202
|
}
|
|
985
1203
|
])
|
|
986
1204
|
);
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
const nextPollAt = new Date(deps.clock.now().getTime() + pollInterval);
|
|
993
|
-
await deps.persistence.updateStage(stageRecord.id, {
|
|
994
|
-
nextPollAt
|
|
995
|
-
});
|
|
996
|
-
}
|
|
997
|
-
} catch (error) {
|
|
998
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
999
|
-
await deps.persistence.withTransaction(async (tx) => {
|
|
1000
|
-
await tx.updateStage(stageRecord.id, {
|
|
1001
|
-
status: "FAILED",
|
|
1002
|
-
completedAt: deps.clock.now(),
|
|
1003
|
-
errorMessage,
|
|
1004
|
-
nextPollAt: null
|
|
1005
|
-
});
|
|
1006
|
-
await tx.updateRun(stageRecord.workflowRunId, {
|
|
1007
|
-
status: "FAILED",
|
|
1008
|
-
completedAt: deps.clock.now()
|
|
1009
|
-
});
|
|
1010
|
-
await tx.appendOutboxEvents(
|
|
1011
|
-
toOutboxEvents2(stageRecord.workflowRunId, [
|
|
1012
|
-
{
|
|
1013
|
-
type: "stage:failed",
|
|
1014
|
-
timestamp: deps.clock.now(),
|
|
1015
|
-
workflowRunId: stageRecord.workflowRunId,
|
|
1016
|
-
stageId: stageRecord.stageId,
|
|
1017
|
-
stageName: stageRecord.stageName,
|
|
1018
|
-
error: errorMessage
|
|
1019
|
-
},
|
|
1020
|
-
{
|
|
1021
|
-
type: "workflow:failed",
|
|
1022
|
-
timestamp: deps.clock.now(),
|
|
1023
|
-
workflowRunId: stageRecord.workflowRunId,
|
|
1024
|
-
error: errorMessage
|
|
1025
|
-
}
|
|
1026
|
-
])
|
|
1205
|
+
}
|
|
1206
|
+
);
|
|
1207
|
+
if (claimResult.status === "stale") {
|
|
1208
|
+
const latestStatus = await deps.persistence.getRunStatus(
|
|
1209
|
+
stageRecord.workflowRunId
|
|
1027
1210
|
);
|
|
1028
|
-
|
|
1211
|
+
if (latestStatus === "CANCELLED") {
|
|
1212
|
+
await markStageCancelled(stageRecord.id, deps);
|
|
1213
|
+
}
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1029
1216
|
failed++;
|
|
1030
1217
|
}
|
|
1031
1218
|
}
|
|
@@ -1250,5 +1437,5 @@ function createPluginRunner(config) {
|
|
|
1250
1437
|
}
|
|
1251
1438
|
|
|
1252
1439
|
export { IdempotencyInProgressError, createKernel, createPluginRunner, definePlugin, loadWorkflowContext, saveStageOutput };
|
|
1253
|
-
//# sourceMappingURL=chunk-
|
|
1254
|
-
//# sourceMappingURL=chunk-
|
|
1440
|
+
//# sourceMappingURL=chunk-5C7LRNM7.js.map
|
|
1441
|
+
//# sourceMappingURL=chunk-5C7LRNM7.js.map
|