pg-workflows 0.9.0 → 0.10.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/dist/client.entry.cjs +48 -12
- package/dist/client.entry.d.cts +37 -10
- package/dist/client.entry.d.ts +37 -10
- package/dist/client.entry.js +1 -1
- package/dist/client.entry.js.map +8 -8
- package/dist/index.cjs +369 -83
- package/dist/index.d.cts +68 -20
- package/dist/index.d.ts +68 -20
- package/dist/index.js +326 -73
- package/dist/index.js.map +10 -10
- package/dist/shared/{chunk-fr76gdwj.js → chunk-nygamc7b.js} +50 -14
- package/dist/shared/chunk-nygamc7b.js.map +16 -0
- package/package.json +1 -1
- package/dist/shared/chunk-fr76gdwj.js.map +0 -16
package/dist/index.js
CHANGED
|
@@ -12,13 +12,16 @@ import {
|
|
|
12
12
|
getWorkflowRun,
|
|
13
13
|
getWorkflowRuns,
|
|
14
14
|
insertWorkflowRun,
|
|
15
|
+
invokeChildWorkflowTimelineKey,
|
|
16
|
+
isInvokeChildWorkflowTimelineEntry,
|
|
15
17
|
runMigrations,
|
|
16
18
|
updateWorkflowRun,
|
|
17
19
|
validateResourceId,
|
|
18
20
|
validateWorkflowId,
|
|
21
|
+
waitForTimelineKey,
|
|
19
22
|
withPostgresTransaction,
|
|
20
23
|
workflow
|
|
21
|
-
} from "./shared/chunk-
|
|
24
|
+
} from "./shared/chunk-nygamc7b.js";
|
|
22
25
|
// src/duration.ts
|
|
23
26
|
import parse from "parse-duration";
|
|
24
27
|
var MS_PER_SECOND = 1000;
|
|
@@ -94,7 +97,7 @@ function parseWorkflowHandler(handler) {
|
|
|
94
97
|
const propertyAccess = node.expression;
|
|
95
98
|
const objectName = propertyAccess.expression.getText(sourceFile);
|
|
96
99
|
const methodName = propertyAccess.name.text;
|
|
97
|
-
if (objectName === "step" && (methodName === "run" || methodName === "waitFor" || methodName === "pause" || methodName === "waitUntil" || methodName === "delay" || methodName === "sleep" || methodName === "poll")) {
|
|
100
|
+
if (objectName === "step" && (methodName === "run" || methodName === "waitFor" || methodName === "pause" || methodName === "waitUntil" || methodName === "delay" || methodName === "sleep" || methodName === "poll" || methodName === "invokeChildWorkflow")) {
|
|
98
101
|
const firstArg = node.arguments[0];
|
|
99
102
|
if (firstArg) {
|
|
100
103
|
const { id, isDynamic } = extractStepId(firstArg);
|
|
@@ -127,7 +130,8 @@ var StepTypeToIcon = {
|
|
|
127
130
|
["pause" /* PAUSE */]: "⏸",
|
|
128
131
|
["waitUntil" /* WAIT_UNTIL */]: "⏲",
|
|
129
132
|
["delay" /* DELAY */]: "⏱",
|
|
130
|
-
["poll" /* POLL */]: "↻"
|
|
133
|
+
["poll" /* POLL */]: "↻",
|
|
134
|
+
["invokeChildWorkflow" /* INVOKE_CHILD_WORKFLOW */]: "↪"
|
|
131
135
|
};
|
|
132
136
|
var defaultLogger = {
|
|
133
137
|
log: (_message) => console.warn(_message),
|
|
@@ -139,6 +143,7 @@ var retrySendOptions = (maxRetries) => ({
|
|
|
139
143
|
retryBackoff: true,
|
|
140
144
|
retryDelay: 1
|
|
141
145
|
});
|
|
146
|
+
var getInvokeChildWorkflowEventName = (childRunId) => `__invoke_child_workflow_completed:${childRunId}`;
|
|
142
147
|
var defaultHeartbeatSeconds = process.env.WORKFLOW_RUN_HEARTBEAT_SECONDS ? Number.parseInt(process.env.WORKFLOW_RUN_HEARTBEAT_SECONDS, 10) : 30;
|
|
143
148
|
|
|
144
149
|
class WorkflowEngine {
|
|
@@ -244,31 +249,57 @@ class WorkflowEngine {
|
|
|
244
249
|
this.workflows.clear();
|
|
245
250
|
return this;
|
|
246
251
|
}
|
|
247
|
-
|
|
248
|
-
let workflowId;
|
|
249
|
-
let input;
|
|
250
|
-
let resourceId;
|
|
251
|
-
let idempotencyKey;
|
|
252
|
-
let options;
|
|
252
|
+
resolveWorkflowRunParameters(refOrParams, inputArg, optionsArg) {
|
|
253
253
|
if (typeof refOrParams === "function" && "id" in refOrParams) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
workflowId = params.workflowId;
|
|
262
|
-
input = params.input;
|
|
263
|
-
resourceId = params.resourceId;
|
|
264
|
-
idempotencyKey = params.idempotencyKey;
|
|
265
|
-
options = params.options;
|
|
254
|
+
return {
|
|
255
|
+
workflowId: refOrParams.id,
|
|
256
|
+
input: inputArg,
|
|
257
|
+
options: optionsArg,
|
|
258
|
+
resourceId: optionsArg?.resourceId,
|
|
259
|
+
idempotencyKey: optionsArg?.idempotencyKey
|
|
260
|
+
};
|
|
266
261
|
}
|
|
267
|
-
|
|
268
|
-
|
|
262
|
+
const params = refOrParams;
|
|
263
|
+
return {
|
|
264
|
+
workflowId: params.workflowId,
|
|
265
|
+
input: params.input,
|
|
266
|
+
resourceId: params.resourceId ?? params.options?.resourceId,
|
|
267
|
+
idempotencyKey: params.idempotencyKey ?? params.options?.idempotencyKey,
|
|
268
|
+
options: params.options
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
async startWorkflow(refOrParams, inputArg, optionsArg) {
|
|
272
|
+
const { workflowId, input, resourceId, idempotencyKey, options } = this.resolveWorkflowRunParameters(refOrParams, inputArg, optionsArg);
|
|
269
273
|
if (!this._started) {
|
|
270
274
|
await this.start(false, { batchSize: options?.batchSize ?? 1 });
|
|
271
275
|
}
|
|
276
|
+
const { run } = await this.createWorkflowRun({
|
|
277
|
+
workflowId,
|
|
278
|
+
input,
|
|
279
|
+
resourceId,
|
|
280
|
+
idempotencyKey,
|
|
281
|
+
options
|
|
282
|
+
});
|
|
283
|
+
this.logger.log("Started workflow run", {
|
|
284
|
+
runId: run.id,
|
|
285
|
+
workflowId
|
|
286
|
+
});
|
|
287
|
+
return run;
|
|
288
|
+
}
|
|
289
|
+
async createWorkflowRun({
|
|
290
|
+
workflowId,
|
|
291
|
+
input,
|
|
292
|
+
resourceId,
|
|
293
|
+
idempotencyKey,
|
|
294
|
+
options,
|
|
295
|
+
parentRunId,
|
|
296
|
+
parentStepId,
|
|
297
|
+
parentResourceId,
|
|
298
|
+
enqueue = true,
|
|
299
|
+
db
|
|
300
|
+
}) {
|
|
301
|
+
validateWorkflowId(workflowId);
|
|
302
|
+
validateResourceId(resourceId);
|
|
272
303
|
const workflow2 = this.workflows.get(workflowId);
|
|
273
304
|
if (!workflow2) {
|
|
274
305
|
throw new WorkflowEngineError(`Unknown workflow ${workflowId}`);
|
|
@@ -285,38 +316,60 @@ class WorkflowEngine {
|
|
|
285
316
|
}
|
|
286
317
|
}
|
|
287
318
|
const initialStepId = workflow2.steps[0]?.id ?? "__start__";
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
};
|
|
307
|
-
await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
|
|
308
|
-
startAfter: new Date,
|
|
309
|
-
expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds,
|
|
310
|
-
...retrySendOptions(insertedRun.maxRetries)
|
|
311
|
-
});
|
|
319
|
+
const timeoutAt = options?.timeout ? new Date(Date.now() + options.timeout) : workflow2.timeout ? new Date(Date.now() + workflow2.timeout) : null;
|
|
320
|
+
const insertRun = async (targetDb) => await insertWorkflowRun({
|
|
321
|
+
resourceId,
|
|
322
|
+
workflowId,
|
|
323
|
+
currentStepId: initialStepId,
|
|
324
|
+
status: "running" /* RUNNING */,
|
|
325
|
+
input,
|
|
326
|
+
maxRetries: options?.retries ?? workflow2.retries ?? 0,
|
|
327
|
+
timeoutAt,
|
|
328
|
+
idempotencyKey,
|
|
329
|
+
parentRunId,
|
|
330
|
+
parentStepId,
|
|
331
|
+
parentResourceId
|
|
332
|
+
}, targetDb);
|
|
333
|
+
const insertAndEnqueue = async (targetDb) => {
|
|
334
|
+
const result = await insertRun(targetDb);
|
|
335
|
+
if (enqueue && result.created) {
|
|
336
|
+
await this.enqueueWorkflowRun(result.run, options, targetDb);
|
|
312
337
|
}
|
|
313
|
-
return
|
|
314
|
-
}
|
|
315
|
-
this.
|
|
338
|
+
return result;
|
|
339
|
+
};
|
|
340
|
+
const { run, created } = db ? await insertAndEnqueue(db) : await withPostgresTransaction(this.boss.getDb(), insertAndEnqueue, this.pool);
|
|
341
|
+
return { run, created };
|
|
342
|
+
}
|
|
343
|
+
async enqueueWorkflowRun(run, options, db) {
|
|
344
|
+
const job = {
|
|
316
345
|
runId: run.id,
|
|
317
|
-
|
|
346
|
+
resourceId: run.resourceId ?? undefined,
|
|
347
|
+
workflowId: run.workflowId,
|
|
348
|
+
input: run.input
|
|
349
|
+
};
|
|
350
|
+
await this.boss.send(WORKFLOW_RUN_QUEUE_NAME, job, {
|
|
351
|
+
startAfter: new Date,
|
|
352
|
+
expireInSeconds: options?.expireInSeconds ?? defaultExpireInSeconds,
|
|
353
|
+
...retrySendOptions(run.maxRetries),
|
|
354
|
+
...db ? { db } : {}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
async notifyParentOfChildTerminalRun(childRun) {
|
|
358
|
+
if (!childRun.parentRunId || !childRun.parentStepId) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const parentRun = await getWorkflowRun({
|
|
362
|
+
runId: childRun.parentRunId,
|
|
363
|
+
resourceId: childRun.parentResourceId ?? undefined
|
|
364
|
+
}, { db: this.db });
|
|
365
|
+
if (!parentRun || parentRun.status === "completed" /* COMPLETED */ || parentRun.status === "failed" /* FAILED */ || parentRun.status === "cancelled" /* CANCELLED */) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
await this.triggerEvent({
|
|
369
|
+
runId: parentRun.id,
|
|
370
|
+
resourceId: parentRun.resourceId ?? undefined,
|
|
371
|
+
eventName: getInvokeChildWorkflowEventName(childRun.id)
|
|
318
372
|
});
|
|
319
|
-
return run;
|
|
320
373
|
}
|
|
321
374
|
async pauseWorkflow({
|
|
322
375
|
runId,
|
|
@@ -348,6 +401,9 @@ class WorkflowEngine {
|
|
|
348
401
|
if (current.status !== "paused" /* PAUSED */) {
|
|
349
402
|
throw new WorkflowEngineError(`Cannot resume workflow run in '${current.status}' status, must be 'paused'`, current.workflowId, runId);
|
|
350
403
|
}
|
|
404
|
+
if (this.getInvokeChildWorkflowStepEntry(current.timeline, current.currentStepId)) {
|
|
405
|
+
return current;
|
|
406
|
+
}
|
|
351
407
|
return this.triggerEvent({
|
|
352
408
|
runId,
|
|
353
409
|
resourceId,
|
|
@@ -367,6 +423,9 @@ class WorkflowEngine {
|
|
|
367
423
|
return run;
|
|
368
424
|
}
|
|
369
425
|
const stepId = run.currentStepId;
|
|
426
|
+
if (this.getInvokeChildWorkflowStepEntry(run.timeline, stepId)) {
|
|
427
|
+
return run;
|
|
428
|
+
}
|
|
370
429
|
const waitForStep = this.getWaitForStepEntry(run.timeline, stepId);
|
|
371
430
|
if (!waitForStep) {
|
|
372
431
|
return run;
|
|
@@ -415,6 +474,7 @@ class WorkflowEngine {
|
|
|
415
474
|
expectedStatuses: ["pending" /* PENDING */, "running" /* RUNNING */, "paused" /* PAUSED */]
|
|
416
475
|
});
|
|
417
476
|
this.logger.log(`cancelled workflow run with id ${runId}`);
|
|
477
|
+
await this.notifyParentOfChildTerminalRun(run);
|
|
418
478
|
return run;
|
|
419
479
|
}
|
|
420
480
|
async triggerEvent({
|
|
@@ -652,6 +712,22 @@ class WorkflowEngine {
|
|
|
652
712
|
}
|
|
653
713
|
const timeoutMs = options?.timeout ? parseDuration(options.timeout) : undefined;
|
|
654
714
|
return this.pollStep({ run, stepId, conditionFn, intervalMs, timeoutMs });
|
|
715
|
+
},
|
|
716
|
+
invokeChildWorkflow: async (stepId, refOrParams, inputArg, optionsArg) => {
|
|
717
|
+
if (!run) {
|
|
718
|
+
throw new WorkflowEngineError("Missing workflow run", workflowId, runId);
|
|
719
|
+
}
|
|
720
|
+
const resolvedChildCall = this.resolveWorkflowRunParameters(refOrParams, inputArg, optionsArg);
|
|
721
|
+
const childWorkflowInvocation = {
|
|
722
|
+
run,
|
|
723
|
+
stepId,
|
|
724
|
+
workflowId: resolvedChildCall.workflowId,
|
|
725
|
+
input: resolvedChildCall.input,
|
|
726
|
+
options: resolvedChildCall.options,
|
|
727
|
+
resourceId: resolvedChildCall.resourceId,
|
|
728
|
+
idempotencyKey: resolvedChildCall.idempotencyKey
|
|
729
|
+
};
|
|
730
|
+
return this.invokeChildWorkflowStep(childWorkflowInvocation);
|
|
655
731
|
}
|
|
656
732
|
};
|
|
657
733
|
let step = { ...baseStep };
|
|
@@ -676,7 +752,7 @@ class WorkflowEngine {
|
|
|
676
752
|
const shouldComplete = run.status === "running" /* RUNNING */ && (noParsedSteps || isLastParsedStep || hasPluginSteps && result !== undefined);
|
|
677
753
|
if (shouldComplete) {
|
|
678
754
|
const normalizedResult = result === undefined ? {} : result;
|
|
679
|
-
await this.updateRun({
|
|
755
|
+
const completedRun = await this.updateRun({
|
|
680
756
|
runId,
|
|
681
757
|
resourceId: scopedResourceId,
|
|
682
758
|
data: {
|
|
@@ -686,6 +762,7 @@ class WorkflowEngine {
|
|
|
686
762
|
jobId: job?.id
|
|
687
763
|
}
|
|
688
764
|
});
|
|
765
|
+
await this.notifyParentOfChildTerminalRun(completedRun);
|
|
689
766
|
this.logger.log("Workflow run completed.", {
|
|
690
767
|
runId,
|
|
691
768
|
workflowId
|
|
@@ -693,7 +770,7 @@ class WorkflowEngine {
|
|
|
693
770
|
}
|
|
694
771
|
} catch (error) {
|
|
695
772
|
if (runId) {
|
|
696
|
-
await this.updateRun({
|
|
773
|
+
const updatedRun = await this.updateRun({
|
|
697
774
|
runId,
|
|
698
775
|
resourceId: scopedResourceId,
|
|
699
776
|
data: {
|
|
@@ -701,6 +778,9 @@ class WorkflowEngine {
|
|
|
701
778
|
jobId: job?.id
|
|
702
779
|
}
|
|
703
780
|
});
|
|
781
|
+
if (updatedRun.status === "completed" /* COMPLETED */ || updatedRun.status === "failed" /* FAILED */ || updatedRun.status === "cancelled" /* CANCELLED */) {
|
|
782
|
+
await this.notifyParentOfChildTerminalRun(updatedRun);
|
|
783
|
+
}
|
|
704
784
|
}
|
|
705
785
|
throw error;
|
|
706
786
|
}
|
|
@@ -712,7 +792,7 @@ class WorkflowEngine {
|
|
|
712
792
|
const run = await getWorkflowRun({ runId }, { db: this.db });
|
|
713
793
|
if (!run || run.status !== "running" /* RUNNING */)
|
|
714
794
|
return;
|
|
715
|
-
await this.updateRun({
|
|
795
|
+
const failedRun = await this.updateRun({
|
|
716
796
|
runId,
|
|
717
797
|
resourceId: run.resourceId ?? undefined,
|
|
718
798
|
data: {
|
|
@@ -720,6 +800,7 @@ class WorkflowEngine {
|
|
|
720
800
|
error: run.error ?? "Workflow run worker died or job expired before completion"
|
|
721
801
|
}
|
|
722
802
|
});
|
|
803
|
+
await this.notifyParentOfChildTerminalRun(failedRun);
|
|
723
804
|
this.logger.log("Marked stuck workflow run as failed", {
|
|
724
805
|
runId,
|
|
725
806
|
workflowId: run.workflowId
|
|
@@ -730,9 +811,195 @@ class WorkflowEngine {
|
|
|
730
811
|
return stepEntry && typeof stepEntry === "object" && "output" in stepEntry ? stepEntry : null;
|
|
731
812
|
}
|
|
732
813
|
getWaitForStepEntry(timeline, stepId) {
|
|
733
|
-
const entry = timeline[
|
|
814
|
+
const entry = timeline[waitForTimelineKey(stepId)];
|
|
734
815
|
return entry && typeof entry === "object" && "waitFor" in entry ? entry : null;
|
|
735
816
|
}
|
|
817
|
+
getInvokeChildWorkflowStepEntry(timeline, stepId) {
|
|
818
|
+
const entry = timeline[invokeChildWorkflowTimelineKey(stepId)];
|
|
819
|
+
return isInvokeChildWorkflowTimelineEntry(entry) ? entry : null;
|
|
820
|
+
}
|
|
821
|
+
getCompletedChildOutput(childRun) {
|
|
822
|
+
return childRun.output === undefined ? {} : childRun.output;
|
|
823
|
+
}
|
|
824
|
+
throwForNonCompletedChild(childRun) {
|
|
825
|
+
throw new WorkflowEngineError(`Child workflow ${childRun.workflowId} ${childRun.status}${childRun.error ? `: ${childRun.error}` : ""}`, childRun.workflowId, childRun.id);
|
|
826
|
+
}
|
|
827
|
+
assertInvokeChildWorkflowStepOwnership({
|
|
828
|
+
childRun,
|
|
829
|
+
parentRun,
|
|
830
|
+
stepId,
|
|
831
|
+
workflowId
|
|
832
|
+
}) {
|
|
833
|
+
const expectedParentResourceId = parentRun.resourceId ?? null;
|
|
834
|
+
const matches = childRun.workflowId === workflowId && childRun.parentRunId === parentRun.id && childRun.parentStepId === stepId && childRun.parentResourceId === expectedParentResourceId;
|
|
835
|
+
if (!matches) {
|
|
836
|
+
throw new WorkflowEngineError(`Idempotency key resolved to workflow run ${childRun.id}, which does not belong to invokeChildWorkflow step '${stepId}'`, workflowId, parentRun.id);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
async invokeChildWorkflowStep({
|
|
840
|
+
run,
|
|
841
|
+
stepId,
|
|
842
|
+
workflowId,
|
|
843
|
+
input,
|
|
844
|
+
resourceId,
|
|
845
|
+
idempotencyKey,
|
|
846
|
+
options
|
|
847
|
+
}) {
|
|
848
|
+
let invokeOutput;
|
|
849
|
+
let hasInvokeOutput = false;
|
|
850
|
+
const childResourceId = resourceId ?? run.resourceId ?? undefined;
|
|
851
|
+
const childIdempotencyKey = idempotencyKey;
|
|
852
|
+
await withPostgresTransaction(this.db, async (db) => {
|
|
853
|
+
const lockedRun = await this.getRun({ runId: run.id, resourceId: run.resourceId ?? undefined }, { exclusiveLock: true, db });
|
|
854
|
+
if (lockedRun.status === "cancelled" /* CANCELLED */ || lockedRun.status === "paused" /* PAUSED */ || lockedRun.status === "failed" /* FAILED */) {
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
const lockedCached = this.getCachedStepEntry(lockedRun.timeline, stepId);
|
|
858
|
+
if (lockedCached?.output !== undefined) {
|
|
859
|
+
invokeOutput = lockedCached.output;
|
|
860
|
+
hasInvokeOutput = true;
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const lockedInvoke = this.getInvokeChildWorkflowStepEntry(lockedRun.timeline, stepId);
|
|
864
|
+
if (lockedInvoke) {
|
|
865
|
+
const existingChildResourceId = "childResourceId" in lockedInvoke.invokeChildWorkflow ? lockedInvoke.invokeChildWorkflow.childResourceId ?? undefined : childResourceId;
|
|
866
|
+
const existingChildRun = await this.getRun({
|
|
867
|
+
runId: lockedInvoke.invokeChildWorkflow.childRunId,
|
|
868
|
+
resourceId: existingChildResourceId
|
|
869
|
+
});
|
|
870
|
+
if (existingChildRun.status === "completed" /* COMPLETED */) {
|
|
871
|
+
invokeOutput = this.getCompletedChildOutput(existingChildRun);
|
|
872
|
+
hasInvokeOutput = true;
|
|
873
|
+
await this.updateRun({
|
|
874
|
+
runId: run.id,
|
|
875
|
+
resourceId: run.resourceId ?? undefined,
|
|
876
|
+
data: {
|
|
877
|
+
timeline: merge(lockedRun.timeline, {
|
|
878
|
+
[stepId]: {
|
|
879
|
+
output: invokeOutput,
|
|
880
|
+
timestamp: new Date
|
|
881
|
+
}
|
|
882
|
+
})
|
|
883
|
+
}
|
|
884
|
+
}, { db });
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
if (existingChildRun.status === "failed" /* FAILED */ || existingChildRun.status === "cancelled" /* CANCELLED */) {
|
|
888
|
+
this.throwForNonCompletedChild(existingChildRun);
|
|
889
|
+
}
|
|
890
|
+
await this.pauseRunForWait({
|
|
891
|
+
run: lockedRun,
|
|
892
|
+
stepId,
|
|
893
|
+
eventName: getInvokeChildWorkflowEventName(existingChildRun.id),
|
|
894
|
+
skipOutput: true,
|
|
895
|
+
db
|
|
896
|
+
});
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
const result = await this.createWorkflowRun({
|
|
900
|
+
workflowId,
|
|
901
|
+
input,
|
|
902
|
+
resourceId: childResourceId,
|
|
903
|
+
idempotencyKey: childIdempotencyKey,
|
|
904
|
+
options,
|
|
905
|
+
parentRunId: run.id,
|
|
906
|
+
parentStepId: stepId,
|
|
907
|
+
parentResourceId: run.resourceId ?? undefined,
|
|
908
|
+
enqueue: true,
|
|
909
|
+
db
|
|
910
|
+
});
|
|
911
|
+
const childRun = result.run;
|
|
912
|
+
if (!result.created) {
|
|
913
|
+
this.assertInvokeChildWorkflowStepOwnership({
|
|
914
|
+
childRun,
|
|
915
|
+
parentRun: lockedRun,
|
|
916
|
+
stepId,
|
|
917
|
+
workflowId
|
|
918
|
+
});
|
|
919
|
+
if (childRun.status === "completed" /* COMPLETED */) {
|
|
920
|
+
invokeOutput = this.getCompletedChildOutput(childRun);
|
|
921
|
+
hasInvokeOutput = true;
|
|
922
|
+
await this.updateRun({
|
|
923
|
+
runId: run.id,
|
|
924
|
+
resourceId: run.resourceId ?? undefined,
|
|
925
|
+
data: {
|
|
926
|
+
timeline: merge(lockedRun.timeline, {
|
|
927
|
+
[invokeChildWorkflowTimelineKey(stepId)]: {
|
|
928
|
+
invokeChildWorkflow: {
|
|
929
|
+
childRunId: childRun.id,
|
|
930
|
+
childWorkflowId: childRun.workflowId,
|
|
931
|
+
childResourceId: childRun.resourceId
|
|
932
|
+
},
|
|
933
|
+
timestamp: new Date
|
|
934
|
+
},
|
|
935
|
+
[stepId]: {
|
|
936
|
+
output: invokeOutput,
|
|
937
|
+
timestamp: new Date
|
|
938
|
+
}
|
|
939
|
+
})
|
|
940
|
+
}
|
|
941
|
+
}, { db });
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
if (childRun.status === "failed" /* FAILED */ || childRun.status === "cancelled" /* CANCELLED */) {
|
|
945
|
+
this.throwForNonCompletedChild(childRun);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
await this.pauseRunForWait({
|
|
949
|
+
run: lockedRun,
|
|
950
|
+
stepId,
|
|
951
|
+
eventName: getInvokeChildWorkflowEventName(childRun.id),
|
|
952
|
+
skipOutput: true,
|
|
953
|
+
db,
|
|
954
|
+
timeline: merge(lockedRun.timeline, {
|
|
955
|
+
[invokeChildWorkflowTimelineKey(stepId)]: {
|
|
956
|
+
invokeChildWorkflow: {
|
|
957
|
+
childRunId: childRun.id,
|
|
958
|
+
childWorkflowId: childRun.workflowId,
|
|
959
|
+
childResourceId: childRun.resourceId
|
|
960
|
+
},
|
|
961
|
+
timestamp: new Date
|
|
962
|
+
}
|
|
963
|
+
})
|
|
964
|
+
});
|
|
965
|
+
}, this.pool);
|
|
966
|
+
if (hasInvokeOutput) {
|
|
967
|
+
return invokeOutput;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
async pauseRunForWait({
|
|
971
|
+
run,
|
|
972
|
+
stepId,
|
|
973
|
+
eventName,
|
|
974
|
+
timeoutEvent,
|
|
975
|
+
skipOutput,
|
|
976
|
+
db,
|
|
977
|
+
timeline
|
|
978
|
+
}) {
|
|
979
|
+
const baseTimeline = timeline ?? run.timeline;
|
|
980
|
+
const waitFor = {};
|
|
981
|
+
if (eventName)
|
|
982
|
+
waitFor.eventName = eventName;
|
|
983
|
+
if (timeoutEvent)
|
|
984
|
+
waitFor.timeoutEvent = timeoutEvent;
|
|
985
|
+
if (skipOutput)
|
|
986
|
+
waitFor.skipOutput = true;
|
|
987
|
+
await this.updateRun({
|
|
988
|
+
runId: run.id,
|
|
989
|
+
resourceId: run.resourceId ?? undefined,
|
|
990
|
+
data: {
|
|
991
|
+
status: "paused" /* PAUSED */,
|
|
992
|
+
currentStepId: stepId,
|
|
993
|
+
pausedAt: new Date,
|
|
994
|
+
timeline: merge(baseTimeline, {
|
|
995
|
+
[waitForTimelineKey(stepId)]: {
|
|
996
|
+
waitFor,
|
|
997
|
+
timestamp: new Date
|
|
998
|
+
}
|
|
999
|
+
})
|
|
1000
|
+
}
|
|
1001
|
+
}, { db });
|
|
1002
|
+
}
|
|
736
1003
|
async runStep({
|
|
737
1004
|
stepId,
|
|
738
1005
|
run,
|
|
@@ -821,21 +1088,7 @@ ${error.stack}` : String(error)
|
|
|
821
1088
|
const timeoutEvent = timeoutDate ? `__timeout_${stepId}` : undefined;
|
|
822
1089
|
await withPostgresTransaction(this.db, async (db) => {
|
|
823
1090
|
const freshRun = await this.getRun({ runId: run.id, resourceId: run.resourceId ?? undefined }, { exclusiveLock: true, db });
|
|
824
|
-
return this.
|
|
825
|
-
runId: run.id,
|
|
826
|
-
resourceId: run.resourceId ?? undefined,
|
|
827
|
-
data: {
|
|
828
|
-
status: "paused" /* PAUSED */,
|
|
829
|
-
currentStepId: stepId,
|
|
830
|
-
pausedAt: new Date,
|
|
831
|
-
timeline: merge(freshRun.timeline, {
|
|
832
|
-
[`${stepId}-wait-for`]: {
|
|
833
|
-
waitFor: { eventName, timeoutEvent },
|
|
834
|
-
timestamp: new Date
|
|
835
|
-
}
|
|
836
|
-
})
|
|
837
|
-
}
|
|
838
|
-
}, { db });
|
|
1091
|
+
return this.pauseRunForWait({ run: freshRun, stepId, eventName, timeoutEvent, db });
|
|
839
1092
|
}, this.pool);
|
|
840
1093
|
if (timeoutDate && timeoutEvent) {
|
|
841
1094
|
try {
|
|
@@ -949,7 +1202,7 @@ ${error.stack}` : String(error)
|
|
|
949
1202
|
pausedAt: new Date,
|
|
950
1203
|
timeline: merge(freshRun.timeline, {
|
|
951
1204
|
[`${stepId}-poll`]: { startedAt: startedAt.toISOString() },
|
|
952
|
-
[
|
|
1205
|
+
[waitForTimelineKey(stepId)]: {
|
|
953
1206
|
waitFor: { timeoutEvent: pollEvent, skipOutput: true },
|
|
954
1207
|
timestamp: new Date
|
|
955
1208
|
}
|
|
@@ -1037,5 +1290,5 @@ export {
|
|
|
1037
1290
|
StepType
|
|
1038
1291
|
};
|
|
1039
1292
|
|
|
1040
|
-
//# debugId=
|
|
1293
|
+
//# debugId=F3273B34BE68C60E64756E2164756E21
|
|
1041
1294
|
//# sourceMappingURL=index.js.map
|