Skip to content

Commit 747dadc

Browse files
continue on failure
1 parent 295c158 commit 747dadc

4 files changed

Lines changed: 118 additions & 4 deletions

File tree

packages/core/orchestration/src/transaction/transaction-orchestrator.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,10 @@ export class TransactionOrchestrator extends EventEmitter {
11921192
isPermanent: boolean,
11931193
response?: unknown
11941194
): Promise<void> {
1195+
const isAsync = step.isCompensating()
1196+
? step.definition.compensateAsync
1197+
: step.definition.async
1198+
11951199
if (isDefined(response) && step.saveResponse) {
11961200
transaction.addResponse(
11971201
step.definition.action!,
@@ -1210,10 +1214,15 @@ export class TransactionOrchestrator extends EventEmitter {
12101214
)
12111215

12121216
if (ret.transactionIsCancelling) {
1213-
return await this.cancelTransaction(transaction, {
1217+
await this.cancelTransaction(transaction, {
12141218
preventExecuteNext: true,
12151219
})
12161220
}
1221+
1222+
if (isAsync && !ret.stopExecution) {
1223+
// Schedule to continue the execution of async steps because they are not awaited on purpose and can be handled by another machine
1224+
await transaction.scheduleRetry(step, 0)
1225+
}
12171226
}
12181227

12191228
/**

packages/modules/workflow-engine-inmemory/integration-tests/__fixtures__/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ export * from "./workflow_2"
33
export * from "./workflow_async"
44
export * from "./workflow_conditional_step"
55
export * from "./workflow_idempotent"
6+
export * from "./workflow_not_idempotent_with_retention"
7+
export * from "./workflow_parallel_async"
68
export * from "./workflow_step_timeout"
79
export * from "./workflow_sync"
810
export * from "./workflow_transaction_timeout"
9-
export * from "./workflow_not_idempotent_with_retention"
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Modules } from "@medusajs/framework/utils"
2+
import {
3+
createStep,
4+
createWorkflow,
5+
parallelize,
6+
StepResponse,
7+
} from "@medusajs/framework/workflows-sdk"
8+
9+
const step_2 = createStep(
10+
{
11+
name: "step_2",
12+
async: true,
13+
},
14+
async (_, { container }) => {
15+
const we = container.resolve(Modules.WORKFLOW_ENGINE)
16+
17+
await we.run("workflow_sub_workflow", {
18+
throwOnError: true,
19+
})
20+
}
21+
)
22+
23+
const parallelStep2Invoke = jest.fn(() => {
24+
throw new Error("Error in parallel step")
25+
})
26+
const step_2_sub = createStep(
27+
{
28+
name: "step_2",
29+
async: true,
30+
},
31+
parallelStep2Invoke
32+
)
33+
34+
const subFlow = createWorkflow(
35+
{
36+
name: "workflow_sub_workflow",
37+
retentionTime: 1000,
38+
},
39+
function (input) {
40+
step_2_sub()
41+
}
42+
)
43+
44+
const step_1 = createStep(
45+
{
46+
name: "step_1",
47+
async: true,
48+
},
49+
jest.fn(() => {
50+
return new StepResponse("step_1")
51+
})
52+
)
53+
54+
const parallelStep3Invoke = jest.fn(() => {
55+
return new StepResponse({
56+
done: true,
57+
})
58+
})
59+
60+
const step_3 = createStep(
61+
{
62+
name: "step_3",
63+
async: true,
64+
},
65+
parallelStep3Invoke
66+
)
67+
68+
createWorkflow(
69+
{
70+
name: "workflow_parallel_async",
71+
retentionTime: 1000,
72+
},
73+
function (input) {
74+
parallelize(step_1(), step_2(), step_3())
75+
}
76+
)

packages/modules/workflow-engine-inmemory/integration-tests/__tests__/index.spec.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { MedusaContainer } from "@medusajs/framework"
12
import {
23
DistributedTransactionType,
34
TransactionState,
@@ -43,7 +44,6 @@ import {
4344
workflowEventGroupIdStep2Mock,
4445
} from "../__fixtures__/workflow_event_group_id"
4546
import { createScheduled } from "../__fixtures__/workflow_scheduled"
46-
import { container, MedusaContainer } from "@medusajs/framework"
4747

4848
jest.setTimeout(60000)
4949

@@ -912,7 +912,6 @@ moduleIntegrationTestRunner<IWorkflowEngineService>({
912912

913913
expect(spy).toHaveBeenCalledTimes(1)
914914

915-
console.log(spy.mock.results)
916915
expect(spy).toHaveReturnedWith(
917916
expect.objectContaining({ output: { testValue: "test" } })
918917
)
@@ -958,6 +957,35 @@ moduleIntegrationTestRunner<IWorkflowEngineService>({
958957
expect(executionsList).toHaveLength(1)
959958
expect(executionsListAfter).toHaveLength(1)
960959
})
960+
961+
it("should display error when multple async steps are running in parallel", (done) => {
962+
void workflowOrcModule.run("workflow_parallel_async", {
963+
input: {},
964+
throwOnError: false,
965+
})
966+
967+
void workflowOrcModule.subscribe({
968+
workflowId: "workflow_parallel_async",
969+
subscriber: (event) => {
970+
if (event.eventType === "onFinish") {
971+
done()
972+
expect(event.errors).toEqual(
973+
expect.arrayContaining([
974+
expect.objectContaining({
975+
action: "step_2",
976+
handlerType: "invoke",
977+
error: expect.objectContaining({
978+
message: "Error in parallel step",
979+
}),
980+
}),
981+
])
982+
)
983+
}
984+
},
985+
})
986+
987+
failTrap(done)
988+
})
961989
})
962990

963991
describe("Cleaner job", function () {

0 commit comments

Comments
 (0)