Skip to content

Commit 8cda65a

Browse files
committed
fix checkpoint
1 parent 3cd9ae9 commit 8cda65a

File tree

3 files changed

+72
-36
lines changed

3 files changed

+72
-36
lines changed

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

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -472,9 +472,6 @@ export class TransactionOrchestrator extends EventEmitter {
472472
)
473473
}
474474

475-
const flow = transaction.getFlow()
476-
const options = TransactionOrchestrator.getWorkflowOptions(flow.modelId)
477-
478475
if (!hasStepTimedOut) {
479476
step.changeStatus(TransactionStepStatus.OK)
480477
}
@@ -485,8 +482,15 @@ export class TransactionOrchestrator extends EventEmitter {
485482
step.changeState(TransactionStepState.DONE)
486483
}
487484

488-
if (step.definition.async || options?.storeExecution) {
485+
let shouldEmit = true
486+
try {
489487
await transaction.saveCheckpoint()
488+
} catch (error) {
489+
if (SkipExecutionError.isSkipExecutionError(error)) {
490+
shouldEmit = false
491+
} else {
492+
throw error
493+
}
490494
}
491495

492496
const cleaningUp: Promise<unknown>[] = []
@@ -499,10 +503,12 @@ export class TransactionOrchestrator extends EventEmitter {
499503

500504
await promiseAll(cleaningUp)
501505

502-
const eventName = step.isCompensating()
503-
? DistributedTransactionEvent.COMPENSATE_STEP_SUCCESS
504-
: DistributedTransactionEvent.STEP_SUCCESS
505-
transaction.emit(eventName, { step, transaction })
506+
if (shouldEmit) {
507+
const eventName = step.isCompensating()
508+
? DistributedTransactionEvent.COMPENSATE_STEP_SUCCESS
509+
: DistributedTransactionEvent.STEP_SUCCESS
510+
transaction.emit(eventName, { step, transaction })
511+
}
506512
}
507513

508514
private static async skipStep(
@@ -605,7 +611,6 @@ export class TransactionOrchestrator extends EventEmitter {
605611
}
606612

607613
const flow = transaction.getFlow()
608-
const options = TransactionOrchestrator.getWorkflowOptions(flow.modelId)
609614

610615
const cleaningUp: Promise<unknown>[] = []
611616

@@ -654,8 +659,15 @@ export class TransactionOrchestrator extends EventEmitter {
654659
}
655660
}
656661

657-
if (step.definition.async || options?.storeExecution) {
662+
let shouldEmit = true
663+
try {
658664
await transaction.saveCheckpoint()
665+
} catch (error) {
666+
if (SkipExecutionError.isSkipExecutionError(error)) {
667+
shouldEmit = false
668+
} else {
669+
throw error
670+
}
659671
}
660672

661673
if (step.hasRetryScheduled()) {
@@ -664,10 +676,12 @@ export class TransactionOrchestrator extends EventEmitter {
664676

665677
await promiseAll(cleaningUp)
666678

667-
const eventName = step.isCompensating()
668-
? DistributedTransactionEvent.COMPENSATE_STEP_FAILURE
669-
: DistributedTransactionEvent.STEP_FAILURE
670-
transaction.emit(eventName, { step, transaction })
679+
if (shouldEmit) {
680+
const eventName = step.isCompensating()
681+
? DistributedTransactionEvent.COMPENSATE_STEP_FAILURE
682+
: DistributedTransactionEvent.STEP_FAILURE
683+
transaction.emit(eventName, { step, transaction })
684+
}
671685
}
672686

673687
private async executeNext(
@@ -696,17 +710,27 @@ export class TransactionOrchestrator extends EventEmitter {
696710
continue
697711
}
698712

699-
console.log("Remaining STEPS", nextSteps.remaining)
713+
console.log(
714+
"Remaining STEPS",
715+
transaction.getFlow().modelId,
716+
nextSteps.remaining,
717+
nextSteps.next.map((step) => step.id),
718+
nextSteps.current ?? "nothing"
719+
)
700720

701721
if (nextSteps.remaining === 0) {
702722
if (transaction.hasTimeout()) {
703723
void transaction.clearTransactionTimeout()
704724
}
705725

706-
await transaction.saveCheckpoint()
726+
// let shouldStop = false
727+
// await transaction.saveCheckpoint()
707728

708729
console.log("FINISH", transaction.getFlow().transactionId)
709730
this.emit(DistributedTransactionEvent.FINISH, { transaction })
731+
// if (shouldStop) {
732+
// return
733+
// }
710734
}
711735

712736
let hasSyncSteps = false
@@ -827,14 +851,15 @@ export class TransactionOrchestrator extends EventEmitter {
827851
] as Parameters<TransactionStepHandler>
828852

829853
if (!isAsync) {
830-
try {
831-
await transaction.saveCheckpoint()
832-
} catch (error) {
833-
if (SkipExecutionError.isSkipExecutionError(error)) {
834-
continueExecution = false
835-
continue
836-
}
837-
}
854+
// try {
855+
// await transaction.saveCheckpoint()
856+
// } catch (error) {
857+
// if (SkipExecutionError.isSkipExecutionError(error)) {
858+
// await transaction.clearStepTimeout(step)
859+
// continueExecution = false
860+
// continue
861+
// }
862+
// }
838863

839864
hasSyncSteps = true
840865

@@ -873,8 +898,8 @@ export class TransactionOrchestrator extends EventEmitter {
873898
)
874899
})
875900
.catch(async (error) => {
876-
console.log("ON Failure SYNC", error)
877901
if (SkipExecutionError.isSkipExecutionError(error)) {
902+
await transaction.clearStepTimeout(step)
878903
continueExecution = false
879904
return
880905
}
@@ -963,6 +988,7 @@ export class TransactionOrchestrator extends EventEmitter {
963988
console.log("ON Failure", error)
964989

965990
if (SkipExecutionError.isSkipExecutionError(error)) {
991+
await transaction.clearStepTimeout(step)
966992
continueExecution = false
967993
return
968994
}

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ moduleIntegrationTestRunner<IWorkflowEngineService>({
116116

117117
it.only("should prevent race continuation of the workflow compensation during retryIntervalAwaiting in background execution", (done) => {
118118
const transactionId = "transaction_id"
119+
const workflowId = "RACE_workflow-1"
119120

120121
const step0InvokeMock = jest.fn()
121122
const step0CompensateMock = jest.fn()
@@ -132,6 +133,7 @@ moduleIntegrationTestRunner<IWorkflowEngineService>({
132133
return new StepResponse("result from step 0")
133134
},
134135
() => {
136+
console.log("step0 compensate")
135137
step0CompensateMock()
136138
}
137139
)
@@ -145,6 +147,7 @@ moduleIntegrationTestRunner<IWorkflowEngineService>({
145147
throw new Error("error from step 1")
146148
},
147149
() => {
150+
console.log("step1 compensate")
148151
step1CompensateMock()
149152
}
150153
)
@@ -160,14 +163,14 @@ moduleIntegrationTestRunner<IWorkflowEngineService>({
160163
return new WorkflowResponse(status)
161164
})
162165

163-
createWorkflow("RACE_workflow-1", function () {
166+
createWorkflow(workflowId, function () {
164167
const build = step0()
165168

166169
const status = subWorkflow.runAsStep({} as any).config({
167170
async: true,
168171
compensateAsync: true,
169172
backgroundExecution: true,
170-
retryIntervalAwaiting: 1,
173+
// retryIntervalAwaiting: 1,
171174
})
172175

173176
const transformedResult = transform({ status }, (data) => {
@@ -182,14 +185,14 @@ moduleIntegrationTestRunner<IWorkflowEngineService>({
182185
})
183186

184187
void workflowOrcModule.subscribe({
185-
workflowId: "workflow-1",
188+
workflowId: workflowId,
186189
transactionId,
187190
subscriber: (event) => {
188191
if (event.eventType === "onFinish") {
189192
expect(step0InvokeMock).toHaveBeenCalledTimes(1)
190193
expect(step0CompensateMock).toHaveBeenCalledTimes(1)
191-
expect(step1InvokeMock.mock.calls.length).toBeGreaterThan(1)
192-
expect(step1CompensateMock.mock.calls.length).toBeGreaterThan(1)
194+
expect(step1InvokeMock).toHaveBeenCalledTimes(1)
195+
expect(step1CompensateMock).toHaveBeenCalledTimes(1)
193196
expect(step2InvokeMock).toHaveBeenCalledTimes(0)
194197
expect(transformMock).toHaveBeenCalledTimes(0)
195198
done()
@@ -198,7 +201,7 @@ moduleIntegrationTestRunner<IWorkflowEngineService>({
198201
})
199202

200203
workflowOrcModule
201-
.run("workflow-1", { transactionId })
204+
.run(workflowId, { transactionId })
202205
.then(({ result }) => {
203206
expect(result).toBe("result from step 0")
204207
})

packages/modules/workflow-engine-inmemory/src/utils/workflow-orchestrator-storage.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,11 @@ export class InMemoryDistributedTransactionStorage
231231
currentFlowLastInvokingStepIndex !== isLatestExecutionFinishedIndex
232232

233233
const compensateShouldBeSkipped =
234-
latestUpdatedFlowLastCompensatingStepIndex ===
234+
(latestUpdatedFlowLastCompensatingStepIndex ===
235235
isLatestExecutionFinishedIndex ||
236-
(currentFlowLastCompensatingStepIndex <
237-
latestUpdatedFlowLastCompensatingStepIndex &&
238-
latestUpdatedFlowLastCompensatingStepIndex !==
239-
isLatestExecutionFinishedIndex)
236+
currentFlowLastCompensatingStepIndex <
237+
latestUpdatedFlowLastCompensatingStepIndex) &&
238+
currentFlowLastCompensatingStepIndex !== isLatestExecutionFinishedIndex
240239

241240
if (
242241
(data.flow.state !== TransactionState.COMPENSATING &&
@@ -246,6 +245,14 @@ export class InMemoryDistributedTransactionStorage
246245
(latestUpdatedFlow.state === TransactionState.COMPENSATING &&
247246
currentFlow.state !== latestUpdatedFlow.state)
248247
) {
248+
console.log("skipping execution", {
249+
currentState: data.flow.state,
250+
latestUpdatedState: latestUpdatedFlow.state,
251+
latestUpdatedFlowLastCompensatingStepIndex,
252+
currentFlowLastCompensatingStepIndex,
253+
currentFlowLastInvokingStepIndex,
254+
latestUpdatedFlowLastInvokingStepIndex,
255+
})
249256
/**
250257
* If the latest execution is ahead of the current execution in terms of completion then we
251258
* should skip to prevent multiple completion/execution of the same step. The same goes for

0 commit comments

Comments
 (0)