pg-workflows 0.6.0 → 0.6.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/dist/index.cjs +237 -167
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +237 -167
- package/dist/index.js.map +5 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -195,15 +195,23 @@ async function runMigrations(db) {
|
|
|
195
195
|
job_id varchar(256)
|
|
196
196
|
);
|
|
197
197
|
`, []);
|
|
198
|
-
await db.executeSql(`
|
|
199
|
-
CREATE INDEX workflow_runs_workflow_id_idx ON workflow_runs USING btree (workflow_id);
|
|
200
|
-
`, []);
|
|
201
198
|
await db.executeSql(`
|
|
202
199
|
CREATE INDEX workflow_runs_created_at_idx ON workflow_runs USING btree (created_at);
|
|
200
|
+
CREATE INDEX workflow_runs_resource_id_created_at_idx ON workflow_runs USING btree (resource_id, created_at DESC);
|
|
201
|
+
CREATE INDEX workflow_runs_status_created_at_idx ON workflow_runs USING btree (status, created_at DESC);
|
|
202
|
+
CREATE INDEX workflow_runs_workflow_id_created_at_idx ON workflow_runs USING btree (workflow_id, created_at DESC);
|
|
203
|
+
CREATE INDEX workflow_runs_resource_id_workflow_id_created_at_idx ON workflow_runs USING btree (resource_id, workflow_id, created_at DESC);
|
|
203
204
|
`, []);
|
|
205
|
+
} else {
|
|
204
206
|
await db.executeSql(`
|
|
205
|
-
|
|
206
|
-
|
|
207
|
+
DROP INDEX IF EXISTS workflow_runs_workflow_id_idx;
|
|
208
|
+
DROP INDEX IF EXISTS workflow_runs_resource_id_idx;
|
|
209
|
+
CREATE INDEX IF NOT EXISTS workflow_runs_created_at_idx ON workflow_runs USING btree (created_at);
|
|
210
|
+
CREATE INDEX IF NOT EXISTS workflow_runs_resource_id_created_at_idx ON workflow_runs USING btree (resource_id, created_at DESC);
|
|
211
|
+
CREATE INDEX IF NOT EXISTS workflow_runs_status_created_at_idx ON workflow_runs USING btree (status, created_at DESC);
|
|
212
|
+
CREATE INDEX IF NOT EXISTS workflow_runs_workflow_id_created_at_idx ON workflow_runs USING btree (workflow_id, created_at DESC);
|
|
213
|
+
CREATE INDEX IF NOT EXISTS workflow_runs_resource_id_workflow_id_created_at_idx ON workflow_runs USING btree (resource_id, workflow_id, created_at DESC);
|
|
214
|
+
`, []);
|
|
207
215
|
}
|
|
208
216
|
}
|
|
209
217
|
|
|
@@ -241,8 +249,7 @@ async function insertWorkflowRun({
|
|
|
241
249
|
status,
|
|
242
250
|
input,
|
|
243
251
|
maxRetries,
|
|
244
|
-
timeoutAt
|
|
245
|
-
timeline
|
|
252
|
+
timeoutAt
|
|
246
253
|
}, db) {
|
|
247
254
|
const runId = generateKSUID("run");
|
|
248
255
|
const now = new Date;
|
|
@@ -272,7 +279,7 @@ async function insertWorkflowRun({
|
|
|
272
279
|
timeoutAt,
|
|
273
280
|
now,
|
|
274
281
|
now,
|
|
275
|
-
|
|
282
|
+
"{}",
|
|
276
283
|
0
|
|
277
284
|
]);
|
|
278
285
|
const insertedRun = result.rows[0];
|
|
@@ -300,7 +307,8 @@ async function getWorkflowRun({
|
|
|
300
307
|
async function updateWorkflowRun({
|
|
301
308
|
runId,
|
|
302
309
|
resourceId,
|
|
303
|
-
data
|
|
310
|
+
data,
|
|
311
|
+
expectedStatuses
|
|
304
312
|
}, db) {
|
|
305
313
|
const now = new Date;
|
|
306
314
|
const updates = ["updated_at = $1"];
|
|
@@ -356,10 +364,20 @@ async function updateWorkflowRun({
|
|
|
356
364
|
values.push(data.jobId);
|
|
357
365
|
paramIndex++;
|
|
358
366
|
}
|
|
359
|
-
const whereClause = resourceId ? `WHERE id = $${paramIndex} AND resource_id = $${paramIndex + 1}` : `WHERE id = $${paramIndex}`;
|
|
360
367
|
values.push(runId);
|
|
368
|
+
const idParam = paramIndex;
|
|
369
|
+
paramIndex++;
|
|
361
370
|
if (resourceId) {
|
|
362
371
|
values.push(resourceId);
|
|
372
|
+
paramIndex++;
|
|
373
|
+
}
|
|
374
|
+
if (expectedStatuses && expectedStatuses.length > 0) {
|
|
375
|
+
values.push(expectedStatuses);
|
|
376
|
+
paramIndex++;
|
|
377
|
+
}
|
|
378
|
+
let whereClause = resourceId ? `WHERE id = $${idParam} AND resource_id = $${idParam + 1}` : `WHERE id = $${idParam}`;
|
|
379
|
+
if (expectedStatuses && expectedStatuses.length > 0) {
|
|
380
|
+
whereClause += ` AND status = ANY($${paramIndex - 1})`;
|
|
363
381
|
}
|
|
364
382
|
const query = `
|
|
365
383
|
UPDATE workflow_runs
|
|
@@ -400,20 +418,28 @@ async function getWorkflowRuns({
|
|
|
400
418
|
values.push(workflowId);
|
|
401
419
|
paramIndex++;
|
|
402
420
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
421
|
+
const cursorIds = [startingAfter, endingBefore].filter(Boolean);
|
|
422
|
+
if (cursorIds.length > 0) {
|
|
423
|
+
const cursorResult = await db.executeSql("SELECT id, created_at FROM workflow_runs WHERE id = ANY($1)", [cursorIds]);
|
|
424
|
+
const cursorMap = new Map;
|
|
425
|
+
for (const row of cursorResult.rows) {
|
|
426
|
+
cursorMap.set(row.id, typeof row.created_at === "string" ? new Date(row.created_at) : row.created_at);
|
|
409
427
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
428
|
+
if (startingAfter) {
|
|
429
|
+
const cursor = cursorMap.get(startingAfter);
|
|
430
|
+
if (cursor) {
|
|
431
|
+
conditions.push(`created_at < $${paramIndex}`);
|
|
432
|
+
values.push(cursor);
|
|
433
|
+
paramIndex++;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (endingBefore) {
|
|
437
|
+
const cursor = cursorMap.get(endingBefore);
|
|
438
|
+
if (cursor) {
|
|
439
|
+
conditions.push(`created_at > $${paramIndex}`);
|
|
440
|
+
values.push(cursor);
|
|
441
|
+
paramIndex++;
|
|
442
|
+
}
|
|
417
443
|
}
|
|
418
444
|
}
|
|
419
445
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
@@ -610,8 +636,7 @@ class WorkflowEngine {
|
|
|
610
636
|
status: "running" /* RUNNING */,
|
|
611
637
|
input,
|
|
612
638
|
maxRetries: options?.retries ?? workflow2.retries ?? 0,
|
|
613
|
-
timeoutAt
|
|
614
|
-
timeline: undefined
|
|
639
|
+
timeoutAt
|
|
615
640
|
}, _db);
|
|
616
641
|
const job = {
|
|
617
642
|
runId: insertedRun.id,
|
|
@@ -642,7 +667,8 @@ class WorkflowEngine {
|
|
|
642
667
|
data: {
|
|
643
668
|
status: "paused" /* PAUSED */,
|
|
644
669
|
pausedAt: new Date
|
|
645
|
-
}
|
|
670
|
+
},
|
|
671
|
+
expectedStatuses: ["running" /* RUNNING */, "pending" /* PENDING */]
|
|
646
672
|
});
|
|
647
673
|
this.logger.log("Paused workflow run", {
|
|
648
674
|
runId,
|
|
@@ -656,6 +682,10 @@ class WorkflowEngine {
|
|
|
656
682
|
options
|
|
657
683
|
}) {
|
|
658
684
|
await this.checkIfHasStarted();
|
|
685
|
+
const current = await this.getRun({ runId, resourceId });
|
|
686
|
+
if (current.status !== "paused" /* PAUSED */) {
|
|
687
|
+
throw new WorkflowEngineError(`Cannot resume workflow run in '${current.status}' status, must be 'paused'`, current.workflowId, runId);
|
|
688
|
+
}
|
|
659
689
|
return this.triggerEvent({
|
|
660
690
|
runId,
|
|
661
691
|
resourceId,
|
|
@@ -675,8 +705,7 @@ class WorkflowEngine {
|
|
|
675
705
|
return run;
|
|
676
706
|
}
|
|
677
707
|
const stepId = run.currentStepId;
|
|
678
|
-
const
|
|
679
|
-
const waitForStep = waitForStepEntry && typeof waitForStepEntry === "object" && "waitFor" in waitForStepEntry ? waitForStepEntry : null;
|
|
708
|
+
const waitForStep = this.getWaitForStepEntry(run.timeline, stepId);
|
|
680
709
|
if (!waitForStep) {
|
|
681
710
|
return run;
|
|
682
711
|
}
|
|
@@ -685,18 +714,21 @@ class WorkflowEngine {
|
|
|
685
714
|
return this.resumeWorkflow({ runId, resourceId });
|
|
686
715
|
}
|
|
687
716
|
if (skipOutput && timeoutEvent) {
|
|
688
|
-
await this.
|
|
689
|
-
runId,
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
717
|
+
await withPostgresTransaction(this.db, async (db) => {
|
|
718
|
+
const freshRun = await this.getRun({ runId, resourceId }, { exclusiveLock: true, db });
|
|
719
|
+
return this.updateRun({
|
|
720
|
+
runId,
|
|
721
|
+
resourceId,
|
|
722
|
+
data: {
|
|
723
|
+
timeline: merge(freshRun.timeline, {
|
|
724
|
+
[stepId]: {
|
|
725
|
+
output: data ?? {},
|
|
726
|
+
timestamp: new Date
|
|
727
|
+
}
|
|
728
|
+
})
|
|
729
|
+
}
|
|
730
|
+
}, { db });
|
|
731
|
+
}, this.pool);
|
|
700
732
|
return this.triggerEvent({ runId, resourceId, eventName: timeoutEvent });
|
|
701
733
|
}
|
|
702
734
|
if (eventName) {
|
|
@@ -717,7 +749,8 @@ class WorkflowEngine {
|
|
|
717
749
|
resourceId,
|
|
718
750
|
data: {
|
|
719
751
|
status: "cancelled" /* CANCELLED */
|
|
720
|
-
}
|
|
752
|
+
},
|
|
753
|
+
expectedStatuses: ["pending" /* PENDING */, "running" /* RUNNING */, "paused" /* PAUSED */]
|
|
721
754
|
});
|
|
722
755
|
this.logger.log(`cancelled workflow run with id ${runId}`);
|
|
723
756
|
return run;
|
|
@@ -742,7 +775,7 @@ class WorkflowEngine {
|
|
|
742
775
|
data
|
|
743
776
|
}
|
|
744
777
|
};
|
|
745
|
-
this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
|
|
778
|
+
await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
|
|
746
779
|
expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds
|
|
747
780
|
});
|
|
748
781
|
this.logger.log(`event ${eventName} sent for workflow run with id ${runId}`);
|
|
@@ -758,10 +791,17 @@ class WorkflowEngine {
|
|
|
758
791
|
async updateRun({
|
|
759
792
|
runId,
|
|
760
793
|
resourceId,
|
|
761
|
-
data
|
|
794
|
+
data,
|
|
795
|
+
expectedStatuses
|
|
762
796
|
}, { db } = {}) {
|
|
763
|
-
const run = await updateWorkflowRun({ runId, resourceId, data }, db ?? this.db);
|
|
797
|
+
const run = await updateWorkflowRun({ runId, resourceId, data, expectedStatuses }, db ?? this.db);
|
|
764
798
|
if (!run) {
|
|
799
|
+
if (expectedStatuses) {
|
|
800
|
+
const current = await getWorkflowRun({ runId, resourceId }, { db: db ?? this.db });
|
|
801
|
+
if (current) {
|
|
802
|
+
throw new WorkflowEngineError(`Cannot update workflow run in '${current.status}' status, expected: ${expectedStatuses.join(", ")}`, current.workflowId, runId);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
765
805
|
throw new WorkflowRunNotFoundError(runId);
|
|
766
806
|
}
|
|
767
807
|
return run;
|
|
@@ -844,36 +884,40 @@ class WorkflowEngine {
|
|
|
844
884
|
throw new WorkflowEngineError("Missing current step id", workflowId, runId);
|
|
845
885
|
}
|
|
846
886
|
if (run.status === "paused" /* PAUSED */) {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
const
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
887
|
+
run = await withPostgresTransaction(this.db, async (db) => {
|
|
888
|
+
const lockedRun = await this.getRun({ runId, resourceId: scopedResourceId }, { exclusiveLock: true, db });
|
|
889
|
+
if (lockedRun.status !== "paused" /* PAUSED */) {
|
|
890
|
+
return lockedRun;
|
|
891
|
+
}
|
|
892
|
+
const waitForStep = this.getWaitForStepEntry(lockedRun.timeline, lockedRun.currentStepId);
|
|
893
|
+
const currentStep = this.getCachedStepEntry(lockedRun.timeline, lockedRun.currentStepId);
|
|
894
|
+
const waitFor = waitForStep?.waitFor;
|
|
895
|
+
const hasCurrentStepOutput = currentStep?.output !== undefined;
|
|
896
|
+
const eventMatches = waitFor && event?.name && (event.name === waitFor.eventName || event.name === waitFor.timeoutEvent) && !hasCurrentStepOutput;
|
|
897
|
+
if (eventMatches) {
|
|
898
|
+
const isTimeout = event?.name === waitFor?.timeoutEvent;
|
|
899
|
+
const skipOutput = waitFor?.skipOutput;
|
|
900
|
+
return this.updateRun({
|
|
901
|
+
runId,
|
|
902
|
+
resourceId: scopedResourceId,
|
|
903
|
+
data: {
|
|
904
|
+
status: "running" /* RUNNING */,
|
|
905
|
+
pausedAt: null,
|
|
906
|
+
resumedAt: new Date,
|
|
907
|
+
jobId: job?.id,
|
|
908
|
+
...skipOutput ? {} : {
|
|
909
|
+
timeline: merge(lockedRun.timeline, {
|
|
910
|
+
[lockedRun.currentStepId]: {
|
|
911
|
+
output: event?.data ?? {},
|
|
912
|
+
...isTimeout ? { timedOut: true } : {},
|
|
913
|
+
timestamp: new Date
|
|
914
|
+
}
|
|
915
|
+
})
|
|
916
|
+
}
|
|
872
917
|
}
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
run = await this.updateRun({
|
|
918
|
+
}, { db });
|
|
919
|
+
}
|
|
920
|
+
return this.updateRun({
|
|
877
921
|
runId,
|
|
878
922
|
resourceId: scopedResourceId,
|
|
879
923
|
data: {
|
|
@@ -882,8 +926,8 @@ class WorkflowEngine {
|
|
|
882
926
|
resumedAt: new Date,
|
|
883
927
|
jobId: job?.id
|
|
884
928
|
}
|
|
885
|
-
});
|
|
886
|
-
}
|
|
929
|
+
}, { db });
|
|
930
|
+
}, this.pool);
|
|
887
931
|
}
|
|
888
932
|
const baseStep = {
|
|
889
933
|
run: async (stepId, handler) => {
|
|
@@ -1013,6 +1057,10 @@ class WorkflowEngine {
|
|
|
1013
1057
|
const stepEntry = timeline[stepId];
|
|
1014
1058
|
return stepEntry && typeof stepEntry === "object" && "output" in stepEntry ? stepEntry : null;
|
|
1015
1059
|
}
|
|
1060
|
+
getWaitForStepEntry(timeline, stepId) {
|
|
1061
|
+
const entry = timeline[`${stepId}-wait-for`];
|
|
1062
|
+
return entry && typeof entry === "object" && "waitFor" in entry ? entry : null;
|
|
1063
|
+
}
|
|
1016
1064
|
async runStep({
|
|
1017
1065
|
stepId,
|
|
1018
1066
|
run,
|
|
@@ -1054,7 +1102,7 @@ class WorkflowEngine {
|
|
|
1054
1102
|
runId: run.id,
|
|
1055
1103
|
resourceId: run.resourceId ?? undefined,
|
|
1056
1104
|
data: {
|
|
1057
|
-
timeline: merge(
|
|
1105
|
+
timeline: merge(persistedRun.timeline, {
|
|
1058
1106
|
[stepId]: {
|
|
1059
1107
|
output,
|
|
1060
1108
|
timestamp: new Date
|
|
@@ -1098,64 +1146,46 @@ ${error.stack}` : String(error)
|
|
|
1098
1146
|
if (cached?.output !== undefined) {
|
|
1099
1147
|
return cached.timedOut ? undefined : cached.output;
|
|
1100
1148
|
}
|
|
1101
|
-
const
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
if (typeof fastForwardConfig === "object" && fastForwardConfig !== null && !Array.isArray(fastForwardConfig)) {
|
|
1106
|
-
const mockData = fastForwardConfig[stepId];
|
|
1107
|
-
if (mockData !== undefined) {
|
|
1108
|
-
output = mockData;
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
run = await this.updateRun({
|
|
1149
|
+
const timeoutEvent = timeoutDate ? `__timeout_${stepId}` : undefined;
|
|
1150
|
+
await withPostgresTransaction(this.db, async (db) => {
|
|
1151
|
+
const freshRun = await this.getRun({ runId: run.id, resourceId: run.resourceId ?? undefined }, { exclusiveLock: true, db });
|
|
1152
|
+
return this.updateRun({
|
|
1113
1153
|
runId: run.id,
|
|
1114
1154
|
resourceId: run.resourceId ?? undefined,
|
|
1115
1155
|
data: {
|
|
1156
|
+
status: "paused" /* PAUSED */,
|
|
1116
1157
|
currentStepId: stepId,
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1158
|
+
pausedAt: new Date,
|
|
1159
|
+
timeline: merge(freshRun.timeline, {
|
|
1160
|
+
[`${stepId}-wait-for`]: {
|
|
1161
|
+
waitFor: { eventName, timeoutEvent },
|
|
1120
1162
|
timestamp: new Date
|
|
1121
1163
|
}
|
|
1122
1164
|
})
|
|
1123
1165
|
}
|
|
1124
|
-
});
|
|
1125
|
-
|
|
1126
|
-
runId: run.id,
|
|
1127
|
-
workflowId: run.workflowId
|
|
1128
|
-
});
|
|
1129
|
-
return output;
|
|
1130
|
-
}
|
|
1131
|
-
const timeoutEvent = timeoutDate ? `__timeout_${stepId}` : undefined;
|
|
1132
|
-
await this.updateRun({
|
|
1133
|
-
runId: run.id,
|
|
1134
|
-
resourceId: run.resourceId ?? undefined,
|
|
1135
|
-
data: {
|
|
1136
|
-
status: "paused" /* PAUSED */,
|
|
1137
|
-
currentStepId: stepId,
|
|
1138
|
-
pausedAt: new Date,
|
|
1139
|
-
timeline: merge(run.timeline, {
|
|
1140
|
-
[`${stepId}-wait-for`]: {
|
|
1141
|
-
waitFor: { eventName, timeoutEvent },
|
|
1142
|
-
timestamp: new Date
|
|
1143
|
-
}
|
|
1144
|
-
})
|
|
1145
|
-
}
|
|
1146
|
-
});
|
|
1166
|
+
}, { db });
|
|
1167
|
+
}, this.pool);
|
|
1147
1168
|
if (timeoutDate && timeoutEvent) {
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1169
|
+
try {
|
|
1170
|
+
const job = {
|
|
1171
|
+
runId: run.id,
|
|
1172
|
+
resourceId: run.resourceId ?? undefined,
|
|
1173
|
+
workflowId: run.workflowId,
|
|
1174
|
+
input: run.input,
|
|
1175
|
+
event: { name: timeoutEvent, data: { date: timeoutDate.toISOString() } }
|
|
1176
|
+
};
|
|
1177
|
+
await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
|
|
1178
|
+
startAfter: timeoutDate.getTime() <= Date.now() ? new Date : timeoutDate,
|
|
1179
|
+
expireInSeconds: defaultExpireInSeconds
|
|
1180
|
+
});
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
await this.updateRun({
|
|
1183
|
+
runId: run.id,
|
|
1184
|
+
resourceId: run.resourceId ?? undefined,
|
|
1185
|
+
data: { status: "running" /* RUNNING */, pausedAt: null }
|
|
1186
|
+
});
|
|
1187
|
+
throw error;
|
|
1188
|
+
}
|
|
1159
1189
|
}
|
|
1160
1190
|
this.logger.log(`Step ${stepId} waiting${eventName ? ` for event "${eventName}"` : ""}${timeoutDate ? ` until ${timeoutDate.toISOString()}` : ""}`, { runId: run.id, workflowId: run.workflowId });
|
|
1161
1191
|
}
|
|
@@ -1180,59 +1210,99 @@ ${error.stack}` : String(error)
|
|
|
1180
1210
|
const pollStateEntry = persistedRun.timeline[`${stepId}-poll`];
|
|
1181
1211
|
const startedAt = pollStateEntry && typeof pollStateEntry === "object" && "startedAt" in pollStateEntry ? new Date(pollStateEntry.startedAt) : new Date;
|
|
1182
1212
|
if (timeoutMs !== undefined && Date.now() >= startedAt.getTime() + timeoutMs) {
|
|
1183
|
-
await this.
|
|
1213
|
+
await withPostgresTransaction(this.db, async (db) => {
|
|
1214
|
+
const freshRun = await this.getRun({ runId: run.id, resourceId: run.resourceId ?? undefined }, { exclusiveLock: true, db });
|
|
1215
|
+
return this.updateRun({
|
|
1216
|
+
runId: run.id,
|
|
1217
|
+
resourceId: run.resourceId ?? undefined,
|
|
1218
|
+
data: {
|
|
1219
|
+
currentStepId: stepId,
|
|
1220
|
+
timeline: merge(freshRun.timeline, {
|
|
1221
|
+
[stepId]: { output: {}, timedOut: true, timestamp: new Date }
|
|
1222
|
+
})
|
|
1223
|
+
}
|
|
1224
|
+
}, { db });
|
|
1225
|
+
}, this.pool);
|
|
1226
|
+
return { timedOut: true };
|
|
1227
|
+
}
|
|
1228
|
+
let result;
|
|
1229
|
+
try {
|
|
1230
|
+
result = await conditionFn();
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
this.logger.error(`Poll conditionFn for step ${stepId} threw an error, treating as non-match and continuing to poll`, error, { runId: run.id, workflowId: run.workflowId });
|
|
1233
|
+
if (timeoutMs !== undefined && Date.now() >= startedAt.getTime() + timeoutMs) {
|
|
1234
|
+
await withPostgresTransaction(this.db, async (db) => {
|
|
1235
|
+
const freshRun = await this.getRun({ runId: run.id, resourceId: run.resourceId ?? undefined }, { exclusiveLock: true, db });
|
|
1236
|
+
return this.updateRun({
|
|
1237
|
+
runId: run.id,
|
|
1238
|
+
resourceId: run.resourceId ?? undefined,
|
|
1239
|
+
data: {
|
|
1240
|
+
currentStepId: stepId,
|
|
1241
|
+
timeline: merge(freshRun.timeline, {
|
|
1242
|
+
[stepId]: { output: {}, timedOut: true, timestamp: new Date }
|
|
1243
|
+
})
|
|
1244
|
+
}
|
|
1245
|
+
}, { db });
|
|
1246
|
+
}, this.pool);
|
|
1247
|
+
return { timedOut: true };
|
|
1248
|
+
}
|
|
1249
|
+
result = false;
|
|
1250
|
+
}
|
|
1251
|
+
if (result !== false) {
|
|
1252
|
+
await withPostgresTransaction(this.db, async (db) => {
|
|
1253
|
+
const freshRun = await this.getRun({ runId: run.id, resourceId: run.resourceId ?? undefined }, { exclusiveLock: true, db });
|
|
1254
|
+
return this.updateRun({
|
|
1255
|
+
runId: run.id,
|
|
1256
|
+
resourceId: run.resourceId ?? undefined,
|
|
1257
|
+
data: {
|
|
1258
|
+
currentStepId: stepId,
|
|
1259
|
+
timeline: merge(freshRun.timeline, {
|
|
1260
|
+
[stepId]: { output: result, timestamp: new Date }
|
|
1261
|
+
})
|
|
1262
|
+
}
|
|
1263
|
+
}, { db });
|
|
1264
|
+
}, this.pool);
|
|
1265
|
+
return { timedOut: false, data: result };
|
|
1266
|
+
}
|
|
1267
|
+
const pollEvent = `__poll_${stepId}`;
|
|
1268
|
+
await withPostgresTransaction(this.db, async (db) => {
|
|
1269
|
+
const freshRun = await this.getRun({ runId: run.id, resourceId: run.resourceId ?? undefined }, { exclusiveLock: true, db });
|
|
1270
|
+
return this.updateRun({
|
|
1184
1271
|
runId: run.id,
|
|
1185
1272
|
resourceId: run.resourceId ?? undefined,
|
|
1186
1273
|
data: {
|
|
1274
|
+
status: "paused" /* PAUSED */,
|
|
1187
1275
|
currentStepId: stepId,
|
|
1188
|
-
|
|
1189
|
-
|
|
1276
|
+
pausedAt: new Date,
|
|
1277
|
+
timeline: merge(freshRun.timeline, {
|
|
1278
|
+
[`${stepId}-poll`]: { startedAt: startedAt.toISOString() },
|
|
1279
|
+
[`${stepId}-wait-for`]: {
|
|
1280
|
+
waitFor: { timeoutEvent: pollEvent, skipOutput: true },
|
|
1281
|
+
timestamp: new Date
|
|
1282
|
+
}
|
|
1190
1283
|
})
|
|
1191
1284
|
}
|
|
1285
|
+
}, { db });
|
|
1286
|
+
}, this.pool);
|
|
1287
|
+
try {
|
|
1288
|
+
await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, {
|
|
1289
|
+
runId: run.id,
|
|
1290
|
+
resourceId: run.resourceId ?? undefined,
|
|
1291
|
+
workflowId: run.workflowId,
|
|
1292
|
+
input: run.input,
|
|
1293
|
+
event: { name: pollEvent, data: {} }
|
|
1294
|
+
}, {
|
|
1295
|
+
startAfter: new Date(Date.now() + intervalMs),
|
|
1296
|
+
expireInSeconds: defaultExpireInSeconds
|
|
1192
1297
|
});
|
|
1193
|
-
|
|
1194
|
-
}
|
|
1195
|
-
const result = await conditionFn();
|
|
1196
|
-
if (result !== false) {
|
|
1298
|
+
} catch (error) {
|
|
1197
1299
|
await this.updateRun({
|
|
1198
1300
|
runId: run.id,
|
|
1199
1301
|
resourceId: run.resourceId ?? undefined,
|
|
1200
|
-
data: {
|
|
1201
|
-
currentStepId: stepId,
|
|
1202
|
-
timeline: merge(persistedRun.timeline, {
|
|
1203
|
-
[stepId]: { output: result, timestamp: new Date }
|
|
1204
|
-
})
|
|
1205
|
-
}
|
|
1302
|
+
data: { status: "running" /* RUNNING */, pausedAt: null }
|
|
1206
1303
|
});
|
|
1207
|
-
|
|
1304
|
+
throw error;
|
|
1208
1305
|
}
|
|
1209
|
-
const pollEvent = `__poll_${stepId}`;
|
|
1210
|
-
await this.updateRun({
|
|
1211
|
-
runId: run.id,
|
|
1212
|
-
resourceId: run.resourceId ?? undefined,
|
|
1213
|
-
data: {
|
|
1214
|
-
status: "paused" /* PAUSED */,
|
|
1215
|
-
currentStepId: stepId,
|
|
1216
|
-
pausedAt: new Date,
|
|
1217
|
-
timeline: merge(persistedRun.timeline, {
|
|
1218
|
-
[`${stepId}-poll`]: { startedAt: startedAt.toISOString() },
|
|
1219
|
-
[`${stepId}-wait-for`]: {
|
|
1220
|
-
waitFor: { timeoutEvent: pollEvent, skipOutput: true },
|
|
1221
|
-
timestamp: new Date
|
|
1222
|
-
}
|
|
1223
|
-
})
|
|
1224
|
-
}
|
|
1225
|
-
});
|
|
1226
|
-
await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, {
|
|
1227
|
-
runId: run.id,
|
|
1228
|
-
resourceId: run.resourceId ?? undefined,
|
|
1229
|
-
workflowId: run.workflowId,
|
|
1230
|
-
input: run.input,
|
|
1231
|
-
event: { name: pollEvent, data: {} }
|
|
1232
|
-
}, {
|
|
1233
|
-
startAfter: new Date(Date.now() + intervalMs),
|
|
1234
|
-
expireInSeconds: defaultExpireInSeconds
|
|
1235
|
-
});
|
|
1236
1306
|
this.logger.log(`Step ${stepId} polling every ${intervalMs}ms...`, {
|
|
1237
1307
|
runId: run.id,
|
|
1238
1308
|
workflowId: run.workflowId
|
|
@@ -1286,5 +1356,5 @@ export {
|
|
|
1286
1356
|
StepType
|
|
1287
1357
|
};
|
|
1288
1358
|
|
|
1289
|
-
//# debugId=
|
|
1359
|
+
//# debugId=0EF998205E7ED0B464756E2164756E21
|
|
1290
1360
|
//# sourceMappingURL=index.js.map
|