4.6.8. Long-Running Workflows

In this chapter, you’ll learn what a long-running workflow is and how to configure it.

What is a Long-Running Workflow?#

By default, when you execute a workflow, you wait until the workflow finishes execution. Once you receive the workflow’s output, the rest of the code is executed.

A long-running workflow is a workflow that continues its execution in the background. You don’t receive its output immediately. Instead, you subscribe to the workflow execution to listen to status changes and receive its result once the execution is finished.


Configure Long-Running Workflows#

A workflow is considered long-running if at least one step has its async configuration set to true.

For example, consider the following workflow and steps:

src/workflows/hello-world.ts
9})10
11const step2 = createStep(12  {13    name: "step-2",14    async: true,15  },16  async () => {17  return new StepResponse({})18  }19)20
21const step3 = createStep("step-3", async () => {22  return new StepResponse("Finished three steps")23})24
25type WorkflowOutput = {26  message: string27}28
29const myWorkflow = createWorkflow<30  {},31  WorkflowOutput32>("hello-world", function () {33  step1()34  step2()35  const message = step3()36
37  return {38    message,39  }40})41
42export default myWorkflow

The second step has in its configuration object async set to true. This indicates that this step is an asynchronous step.

Important

An asynchronous step must return for the execution to continue.

So, when you execute the hello-world workflow, it continues its execution in the background once it reaches the second step.


Access Long-Running Workflow Status and Result#

To access the status and result of a long-running workflow, use the workflow engine registered in the Medusa Container. The workflow engine provides methods to access and subscribe to workflow executions.

For example:

src/api/store/workflows/route.ts
10
11  const workflowEngineModuleService = req.scope.resolve<12    IWorkflowEngineService13  >(14    ModuleRegistrationName.WORKFLOW_ENGINE15  )16
17  const subscriptionOptions = {18    workflowId: "hello-world",19    transactionId: transaction.transactionId,20    subscriberId: "hello-world-subscriber",21  }22
23  await workflowEngineModuleService.subscribe({24    ...subscriptionOptions,25    subscriber: async (data) => {26      if (data.eventType === "onFinish") {27        console.log("Finished execution", data.result)28        // unsubscribe29        await workflowEngineModuleService.unsubscribe({30          ...subscriptionOptions,31          subscriberOrId: subscriptionOptions.subscriberId,32        })33      } else if (data.eventType === "onStepFailure") {34        console.log("Workflow failed", data.step)35      }36    },37  })38
39  res.send(result)40}

In the above example, you execute the long-running workflow hello-world. You then resolve the workflow engine from the Medusa container and use its subscribe method to listen to changes in the workflow execution’s status.

The subscribe method accepts an object having three properties:

workflowIdstring
The name of the workflow.
transactionIdstring
The ID of the workflow exection's transaction. The transaction's details are returned in the response of the workflow execution.
subscriberstring
The function executed when the workflow execution's status changes. The function receives a data object. It has an eventType property, which you use to check the status of the workflow execution.

Once the workflow execution finishes, the subscriber function is executed with the eventType of the received parameter set to onFinish. The workflow’s output is set in the result property of the parameter.

You can unsubscribe from the workflow using the workflow engine's unsubscribe method, which requires the same object parameter as the subscribe method.

Was this chapter helpful?