fix(orchestration): Prevent workf. cancellation to execute while rescheduling (#12903)

**What**
Currently, when cancelling async workflows, the step will get rescheduled while the current worker try to continue the execution leading to concurrency failure on compensation. This pr prevent the current worker from executing while an async step gets rescheduled

Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2025-07-16 14:44:09 +00:00
committed by GitHub
co-authored by Carlos R. L. Rodrigues
parent eb83954f23
commit c5d609d09c
9 changed files with 305 additions and 63 deletions
@@ -1185,7 +1185,9 @@ export class TransactionOrchestrator extends EventEmitter {
)
if (ret.transactionIsCancelling) {
return await this.cancelTransaction(transaction)
await this.cancelTransaction(transaction, {
preventExecuteNext: true,
})
}
if (isAsync && !ret.stopExecution) {
@@ -1204,6 +1206,10 @@ export class TransactionOrchestrator extends EventEmitter {
isPermanent: boolean,
response?: unknown
): Promise<void> {
const isAsync = step.isCompensating()
? step.definition.compensateAsync
: step.definition.async
if (isDefined(response) && step.saveResponse) {
transaction.addResponse(
step.definition.action!,
@@ -1222,7 +1228,14 @@ export class TransactionOrchestrator extends EventEmitter {
)
if (ret.transactionIsCancelling) {
return await this.cancelTransaction(transaction)
await this.cancelTransaction(transaction, {
preventExecuteNext: true,
})
}
if (isAsync && !ret.stopExecution) {
// Schedule to continue the execution of async steps because they are not awaited on purpose and can be handled by another machine
await transaction.scheduleRetry(step, 0)
}
}
@@ -1287,7 +1300,8 @@ export class TransactionOrchestrator extends EventEmitter {
* @param transaction - The transaction to be reverted
*/
public async cancelTransaction(
transaction: DistributedTransactionType
transaction: DistributedTransactionType,
options?: { preventExecuteNext?: boolean }
): Promise<void> {
if (transaction.modelId !== this.id) {
throw new MedusaError(
@@ -1319,6 +1333,10 @@ export class TransactionOrchestrator extends EventEmitter {
await transaction.saveCheckpoint()
if (options?.preventExecuteNext) {
return
}
await this.executeNext(transaction)
}