fix(orchestration): Use the step definition max retries on set step failure (#13319)

* fix(orchestration): Use the step definition max retries on set step failure

* Create sweet-turkeys-wait.md

* allow to force permanent failure

* update changeset
This commit is contained in:
Adrien de Peretti authored and GitHub committed 2025-08-28 14:35:31 +02:00
1 parent cbaa403744
commit ff152e7ace
9 files changed
+64 -15

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
---
"@medusajs/orchestration": patch
"@medusajs/workflows-sdk": patch
"@medusajs/workflow-engine-inmemory": patch
"@medusajs/workflow-engine-redis": patch
---
fix(orchestration): Use the step definition max retries on set step failure
@@ -1795,12 +1795,14 @@ export class TransactionOrchestrator extends EventEmitter {
handler, handler,
transaction, transaction,
onLoad, onLoad,
forcePermanentFailure,
}: { }: {
responseIdempotencyKey: string responseIdempotencyKey: string
error?: Error | any error?: Error | any
handler?: TransactionStepHandler handler?: TransactionStepHandler
transaction?: DistributedTransactionType transaction?: DistributedTransactionType
onLoad?: (transaction: DistributedTransactionType) => Promise<void> | void onLoad?: (transaction: DistributedTransactionType) => Promise<void> | void
forcePermanentFailure?: boolean
}): Promise<DistributedTransactionType> { }): Promise<DistributedTransactionType> {
const [curTransaction, step] = const [curTransaction, step] =
await TransactionOrchestrator.getTransactionAndStepFromIdempotencyKey( await TransactionOrchestrator.getTransactionAndStepFromIdempotencyKey(
@@ -1822,7 +1824,8 @@ export class TransactionOrchestrator extends EventEmitter {
curTransaction, curTransaction,
step, step,
error, error,
0 // On permanent failure, the step should not consider any retries
forcePermanentFailure ? 0 : step.definition.maxRetries
) )
if (ret.transactionIsCancelling) { if (ret.transactionIsCancelling) {
@@ -467,7 +467,8 @@ export class LocalWorkflow {
idempotencyKey: string, idempotencyKey: string,
error?: Error | any, error?: Error | any,
context?: Context, context?: Context,
subscribe?: DistributedTransactionEvents subscribe?: DistributedTransactionEvents,
forcePermanentFailure?: boolean
): Promise<DistributedTransactionType> { ): Promise<DistributedTransactionType> {
this.medusaContext = context this.medusaContext = context
const { handler, orchestrator } = this.workflow const { handler, orchestrator } = this.workflow
@@ -483,6 +484,7 @@ export class LocalWorkflow {
error, error,
handler: handler(this.container_, context), handler: handler(this.container_, context),
onLoad: this.onLoad.bind(this), onLoad: this.onLoad.bind(this),
forcePermanentFailure,
}) })
try { try {
@@ -8,7 +8,7 @@ import { Context, LoadedModule, MedusaContainer } from "@medusajs/types"
type BaseFlowRunOptions = { type BaseFlowRunOptions = {
context?: Context context?: Context
resultFrom?: string | string[] | Symbol resultFrom?: string | Symbol
throwOnError?: boolean throwOnError?: boolean
logOnError?: boolean logOnError?: boolean
events?: DistributedTransactionEvents events?: DistributedTransactionEvents
@@ -29,6 +29,7 @@ export type FlowRegisterStepFailureOptions<TData = unknown> =
BaseFlowRunOptions & { BaseFlowRunOptions & {
idempotencyKey: string idempotencyKey: string
response?: TData response?: TData
forcePermanentFailure?: boolean
} }
export type FlowCancelOptions = { export type FlowCancelOptions = {
@@ -71,6 +71,14 @@ function createContextualWorkflowRunner<
resultFrom, resultFrom,
isCancel = false, isCancel = false,
container: executionContainer, container: executionContainer,
forcePermanentFailure,
}: {
throwOnError?: boolean
logOnError?: boolean
resultFrom?: string | Symbol
isCancel?: boolean
container?: LoadedModule[] | MedusaContainer
forcePermanentFailure?: boolean
}, },
transactionOrIdOrIdempotencyKey: DistributedTransactionType | string, transactionOrIdOrIdempotencyKey: DistributedTransactionType | string,
input: unknown, input: unknown,
@@ -107,13 +115,15 @@ function createContextualWorkflowRunner<
context.isCancelling = isCancel context.isCancelling = isCancel
const args = [ const args = [transactionOrIdOrIdempotencyKey, input, context, events]
transactionOrIdOrIdempotencyKey,
input, if (method === originalRegisterStepFailure) {
context, // Only available on registerStepFailure
events, args.push(forcePermanentFailure)
flowMetadata, } else {
] args.push(flowMetadata)
}
const transaction = (await method.apply( const transaction = (await method.apply(
method, method,
args args
@@ -161,7 +171,8 @@ function createContextualWorkflowRunner<
}) })
} }
} else { } else {
result = transaction.getContext().invoke?.[resultFrom] result =
resultFrom && transaction.getContext().invoke?.[resultFrom.toString()]
} }
return { return {
@@ -263,6 +274,7 @@ function createContextualWorkflowRunner<
resultFrom, resultFrom,
events, events,
container, container,
forcePermanentFailure,
}: FlowRegisterStepFailureOptions = { }: FlowRegisterStepFailureOptions = {
idempotencyKey: "", idempotencyKey: "",
} }
@@ -288,6 +300,7 @@ function createContextualWorkflowRunner<
resultFrom, resultFrom,
container, container,
logOnError, logOnError,
forcePermanentFailure,
}, },
idempotencyKey, idempotencyKey,
response, response,
@@ -40,6 +40,13 @@ type RegisterStepSuccessOptions<T> = Omit<
"transactionId" | "input" "transactionId" | "input"
> >
type RegisterStepFailureOptions<T> = Omit<
WorkflowOrchestratorRunOptions<T>,
"transactionId" | "input"
> & {
forcePermanentFailure?: boolean
}
type IdempotencyKeyParts = { type IdempotencyKeyParts = {
workflowId: string workflowId: string
transactionId: string transactionId: string
@@ -450,7 +457,7 @@ export class WorkflowOrchestratorService {
}: { }: {
idempotencyKey: string | IdempotencyKeyParts idempotencyKey: string | IdempotencyKeyParts
stepResponse: unknown stepResponse: unknown
options?: RegisterStepSuccessOptions<T> options?: RegisterStepFailureOptions<T>
}) { }) {
const { const {
context, context,
@@ -458,6 +465,7 @@ export class WorkflowOrchestratorService {
resultFrom, resultFrom,
container, container,
events: eventHandlers, events: eventHandlers,
forcePermanentFailure = false,
} = options ?? {} } = options ?? {}
let { throwOnError } = options ?? {} let { throwOnError } = options ?? {}
@@ -484,6 +492,7 @@ export class WorkflowOrchestratorService {
throwOnError: false, throwOnError: false,
logOnError, logOnError,
events, events,
forcePermanentFailure,
response: stepResponse, response: stepResponse,
container: container ?? this.container_, container: container ?? this.container_,
}) })
@@ -240,7 +240,9 @@ export class WorkflowsModuleService<
}: { }: {
idempotencyKey: string | object idempotencyKey: string | object
stepResponse: unknown stepResponse: unknown
options?: Record<string, any> options?: Record<string, any> & {
forcePermanentFailure?: boolean
}
}, },
@MedusaContext() context: Context = {} @MedusaContext() context: Context = {}
) { ) {
@@ -48,6 +48,13 @@ type RegisterStepSuccessOptions<T> = Omit<
"transactionId" | "input" "transactionId" | "input"
> >
type RegisterStepFailureOptions<T> = Omit<
WorkflowOrchestratorRunOptions<T>,
"transactionId" | "input"
> & {
forcePermanentFailure?: boolean
}
type IdempotencyKeyParts = { type IdempotencyKeyParts = {
workflowId: string workflowId: string
transactionId: string transactionId: string
@@ -493,7 +500,7 @@ export class WorkflowOrchestratorService {
}: { }: {
idempotencyKey: string | IdempotencyKeyParts idempotencyKey: string | IdempotencyKeyParts
stepResponse: unknown stepResponse: unknown
options?: RegisterStepSuccessOptions<T> options?: RegisterStepFailureOptions<T>
}) { }) {
const { const {
context, context,
@@ -501,6 +508,7 @@ export class WorkflowOrchestratorService {
resultFrom, resultFrom,
container, container,
events: eventHandlers, events: eventHandlers,
forcePermanentFailure,
} = options ?? {} } = options ?? {}
let { throwOnError } = options ?? {} let { throwOnError } = options ?? {}
@@ -529,6 +537,7 @@ export class WorkflowOrchestratorService {
events, events,
response: stepResponse, response: stepResponse,
container: container ?? this.container_, container: container ?? this.container_,
forcePermanentFailure,
}) })
if (ret.transaction.hasFinished()) { if (ret.transaction.hasFinished()) {
@@ -250,7 +250,9 @@ export class WorkflowsModuleService<
}: { }: {
idempotencyKey: string | object idempotencyKey: string | object
stepResponse: unknown stepResponse: unknown
options?: Record<string, any> options?: Record<string, any> & {
forcePermanentFailure?: boolean
}
}, },
@MedusaContext() context: Context = {} @MedusaContext() context: Context = {}
) { ) {