fix(workflows-sdk): Miss match context usage within run as step (#12449)

**What**

Currently, runAsStep keep reference of the workflow context that is being run as step, except that the step is composed for the current workflow composition and not the workflow being run as a step. Therefore, the context are currently miss matched leading to wrong configuration being used in case of async workflows.

**BUG**
This fix allow the runAsStep to use the current composition context to configure the step for the sub workflow to be run

**BUG BREAKING**
fix the step config wrongly used to wrap async step handlers. Now steps configured async through .config that returns a new step response will indeed marked itself as success without the need for background execution or calling setStepSuccess (as it was expected originally)

**FEATURE**
This pr also add support for cancelling running transaction, the transaction will be marked as being cancelled, once the current step finished, it will cancel the transaction to start compensating all previous steps including itself

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-05-14 15:28:16 +02:00
committed by GitHub
parent ab22faaa52
commit 7fdbf2a965
19 changed files with 603 additions and 64 deletions

View File

@@ -182,7 +182,7 @@ export function applyStep<
compensateFn,
})
wrapAsyncHandler(stepConfig, handler)
wrapAsyncHandler(newConfig, handler)
this.handlers.set(newStepName, handler)

View File

@@ -184,11 +184,16 @@ export function createWorkflow<TData, TResult, THooks extends any[]>(
}: {
input: TData
}): ReturnType<StepFunction<TData, TResult>> => {
// Get current workflow composition context
const workflowCompositionContext =
global[OrchestrationUtils.SymbolMedusaWorkflowComposerContext]
const runAsAsync = workflowCompositionContext.isAsync || context.isAsync
const step = createStep(
{
name: `${name}-as-step`,
async: context.isAsync,
nested: context.isAsync, // if async we flag this is a nested transaction
async: runAsAsync,
nested: runAsAsync, // if async we flag this is a nested transaction
},
async (stepInput: TData, stepContext) => {
const { container, ...sharedContext } = stepContext
@@ -206,7 +211,7 @@ export function createWorkflow<TData, TResult, THooks extends any[]>(
}
let transaction
if (workflowEngine && context.isAsync) {
if (workflowEngine && runAsAsync) {
transaction = await workflowEngine.run(name, {
input: stepInput as any,
context: executionContext,
@@ -221,7 +226,7 @@ export function createWorkflow<TData, TResult, THooks extends any[]>(
return new StepResponse(
transaction.result,
context.isAsync ? stepContext.transactionId : transaction
runAsAsync ? stepContext.transactionId : transaction
)
},
async (transaction, stepContext) => {
@@ -246,7 +251,7 @@ export function createWorkflow<TData, TResult, THooks extends any[]>(
const transactionId = step.__step__ + "-" + stepContext.transactionId
if (workflowEngine && context.isAsync) {
if (workflowEngine && runAsAsync) {
await workflowEngine.cancel(name, {
transactionId: transactionId,
context: executionContext,