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.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
- CREATE INDEX workflow_runs_resource_id_idx ON workflow_runs USING btree (resource_id);
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
- JSON.stringify(timeline ?? {}),
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
- if (startingAfter) {
404
- const cursorResult = await db.executeSql("SELECT created_at FROM workflow_runs WHERE id = $1 LIMIT 1", [startingAfter]);
405
- if (cursorResult.rows[0]?.created_at) {
406
- conditions.push(`created_at < $${paramIndex}`);
407
- values.push(typeof cursorResult.rows[0].created_at === "string" ? new Date(cursorResult.rows[0].created_at) : cursorResult.rows[0].created_at);
408
- paramIndex++;
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
- if (endingBefore) {
412
- const cursorResult = await db.executeSql("SELECT created_at FROM workflow_runs WHERE id = $1 LIMIT 1", [endingBefore]);
413
- if (cursorResult.rows[0]?.created_at) {
414
- conditions.push(`created_at > $${paramIndex}`);
415
- values.push(typeof cursorResult.rows[0].created_at === "string" ? new Date(cursorResult.rows[0].created_at) : cursorResult.rows[0].created_at);
416
- paramIndex++;
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 waitForStepEntry = run.timeline[`${stepId}-wait-for`];
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.updateRun({
689
- runId,
690
- resourceId,
691
- data: {
692
- timeline: merge(run.timeline, {
693
- [stepId]: {
694
- output: data ?? {},
695
- timestamp: new Date
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
- const waitForStepEntry = run.timeline[`${run.currentStepId}-wait-for`];
848
- const waitForStep = waitForStepEntry && typeof waitForStepEntry === "object" && "waitFor" in waitForStepEntry ? waitForStepEntry : null;
849
- const currentStep = this.getCachedStepEntry(run.timeline, run.currentStepId);
850
- const waitFor = waitForStep?.waitFor;
851
- const hasCurrentStepOutput = currentStep?.output !== undefined;
852
- const eventMatches = waitFor && event?.name && (event.name === waitFor.eventName || event.name === waitFor.timeoutEvent) && !hasCurrentStepOutput;
853
- if (eventMatches) {
854
- const isTimeout = event?.name === waitFor?.timeoutEvent;
855
- const skipOutput = waitFor?.skipOutput;
856
- run = await this.updateRun({
857
- runId,
858
- resourceId: scopedResourceId,
859
- data: {
860
- status: "running" /* RUNNING */,
861
- pausedAt: null,
862
- resumedAt: new Date,
863
- jobId: job?.id,
864
- ...skipOutput ? {} : {
865
- timeline: merge(run.timeline, {
866
- [run.currentStepId]: {
867
- output: event?.data ?? {},
868
- ...isTimeout ? { timedOut: true } : {},
869
- timestamp: new Date
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
- } else {
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(run.timeline, {
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 fastForwardConfig = persistedRun.timeline.__fastForward;
1102
- if (fastForwardConfig && eventName !== PAUSE_EVENT_NAME) {
1103
- let output = {};
1104
- if (eventName) {
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
- timeline: merge(run.timeline, {
1118
- [stepId]: {
1119
- output,
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
- this.logger.log(`Step ${stepId} fast-forwarded`, {
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
- const job = {
1149
- runId: run.id,
1150
- resourceId: run.resourceId ?? undefined,
1151
- workflowId: run.workflowId,
1152
- input: run.input,
1153
- event: { name: timeoutEvent, data: { date: timeoutDate.toISOString() } }
1154
- };
1155
- await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
1156
- startAfter: timeoutDate.getTime() <= Date.now() ? new Date : timeoutDate,
1157
- expireInSeconds: defaultExpireInSeconds
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.updateRun({
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
- timeline: merge(persistedRun.timeline, {
1189
- [stepId]: { output: {}, timedOut: true, timestamp: new Date }
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
- return { timedOut: true };
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
- return { timedOut: false, data: result };
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=3C42BBABB5FBDC4364756E2164756E21
1359
+ //# debugId=0EF998205E7ED0B464756E2164756E21
1290
1360
  //# sourceMappingURL=index.js.map