docs: documentation updates for v2.10.2 (#13500)

This commit is contained in:
Shahed Nasser
2025-09-15 13:56:50 +03:00
committed by GitHub
parent ebf33bea43
commit 5589b7351a
9 changed files with 608 additions and 63 deletions

View File

@@ -14,28 +14,25 @@ The Index Module is experimental and still in development, so it is subject to c
## What is the Index Module?
The Index Module is a tool to perform highly performant queries across modules, for example, to filter linked modules.
The Index Module is a tool to perform high-performance queries across modules, for example, to filter linked modules.
While modules share the same database by default, Medusa [isolates modules](../../modules/isolation/page.mdx) to allow using external data sources or different database types.
So, when you retrieve data across modules using Query, Medusa aggregates the data coming from different modules to create the end result. This approach limits your ability to filter data by linked modules. For example, you can't filter products (created in the Product Module) by their brand (created in the Brand Module).
The Index Module solves this problem by ingesting data into a central data store on application startup. The data store has a relational structure that enables efficiently filtering data ingested from different modules (and their data stores). So, when you retrieve data with the Index Module, you're retrieving it from the Index' data store, not the original data source.
The Index Module solves this problem by ingesting data into a central data store on application startup. The data store has a relational structure that enables efficient filtering of data ingested from different modules (and their data stores). So, when you retrieve data with the Index Module, you're retrieving it from the Index Module's data store, not the original data source.
![Diagram showcasing how data is retrieved from the Index Module's data store](https://res.cloudinary.com/dza7lstvk/image/upload/v1747988533/Medusa%20Book/index-module_epurmt.jpg)
### Ingested Data Models
Currently, only the following core data models are ingested into Index when you install it:
All core data models in Medusa are ingested, including `Product`, `Price`, `SalesChannel`, and more. You can also index custom data models if they are linked to an ingested data model. You'll learn more about this in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section.
- `Product`
- `ProductVariant`
- `Price`
- `SalesChannel`
<Note>
Consequently, you can only index custom data models if they are linked to an ingested data model. You'll learn more about this in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section.
Prior to [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2), only the `Product`, `ProductVariant`, `Price`, and `SalesChannel` data models were ingested. Make sure to update to the latest version to ingest all core data models.
Future versions may add more data models to the list.
</Note>
---
@@ -67,7 +64,7 @@ Finally, run the migrations to create the necessary tables for the Index Module
npx medusa db:migrate
```
The index module only ingests data when you start your Medusa server. So, to ingest the [currently supported data models](#ingested-data-models), start the Medusa application:
The Index Module only ingests data when you start your Medusa server. So, to ingest the [currently supported data models](#ingested-data-models), start the Medusa application:
```bash npm2yarn
npm run dev
@@ -181,7 +178,7 @@ Read-only links are not supported by the Index Module.
For example, assuming you have a Brand Module with a Brand data model (as explained in the [Customizations](../../../customization/custom-features/module/page.mdx)), you can ingest it into the Index Module using the `filterable` property in its link definition to the Product data model:
export const filterableHighlights = [
["12", "filterable", "Inject Brand by setting its filterable properties."]
["12", "filterable", "Ingest Brand by setting its filterable properties."]
]
```ts title="src/links/product-brand.ts" highlights={filterableHighlights}

View File

@@ -0,0 +1,131 @@
export const metadata = {
title: `${pageNumber} Locking Operations in Workflows`,
}
# {metadata.title}
In this chapter, youll learn how to lock operations in your workflows to avoid race conditions and ensure data consistency.
## What is a Lock?
A lock is a mechanism that restricts multiple accesses to a resource or a piece of code, preventing multiple processes from modifying it simultaneously.
Locks are particularly useful in workflows where concurrent executions may lead to commerce risks. For example, Medusa uses locks in its cart workflows to prevent issues like overselling products or double charging customers.
The [Locking Module](!resources!/infrastructure-modules/locking) handles the locking mechanism using the underlying provider. You can use the Locking Module's service in your workflows to create locks around critical sections of your code.
---
## How to Use Locks in Workflows
Medusa provides two steps that you can use to create locks in your workflows:
- `acquireLockStep`: Attempt to acquire a lock. If the lock is already held by another process, this step will wait until the lock is released. It will fail if a timeout occurs before acquiring the lock.
- `releaseLockStep`: Release a previously acquired lock.
You can use these steps in your workflows to ensure that only one instance of a workflow can modify a resource at a time.
For example:
export const workflowLockHighlights = [
["13", "acquireLockStep", "Acquire a lock on the order."],
["21", "chargeCustomerStep", "Perform an operation once the lock is acquired."],
["23", "releaseLockStep", "Release the lock after the operation is complete."]
]
```ts title="src/workflows/charge-customer.ts" highlights={workflowLockHighlights}
import { createWorkflow } from "@medusajs/framework/workflows-sdk"
import { acquireLockStep, releaseLockStep } from "@medusajs/medusa/core-flows"
import { chargeCustomerStep } from "./steps/charge-customer-step"
type WorkflowInput = {
customer_id: string;
order_id: string;
}
export const chargeCustomerWorkflow = createWorkflow(
"charge-customer",
(input: WorkflowInput) => {
acquireLockStep({
key: input.order_id,
// Attempt to acquire the lock for two seconds before timing out
timeout: 2,
// Lock is only held for a maximum of ten seconds
ttl: 10,
})
chargeCustomerStep(input)
releaseLockStep({
key: input.order_id,
})
}
)
```
In this example, the workflow attempts to acquire a lock on an order using its ID as the lock key.
Once the lock is acquired, it executes the `chargeCustomerStep`. After the step is complete, it releases the lock using the `releaseLockStep`.
If the lock cannot be acquired within the specified timeout period, the `acquireLockStep` will throw an error, and the workflow will fail.
<Note title="Tip">
If an error occurs in the workflow after a lock is acquired with `acquireLockStep`, the step's compensation function will release the lock automatically.
</Note>
### Locking Steps API
Refer to the [acquireLockStep](!resources!/references/medusa-workflows/steps/acquireLockStep) and [releaseLockStep](!resources!/references/medusa-workflows/steps/releaseLockStep) for more information on the inputs of these steps.
---
## How to Use Locks in Workflow Steps
You can alternatively acquire and release locks within steps by resolving the Locking Module's service and using its `acquire` and `release` methods.
<Note type="warning">
Do not acquire locks within a workflow and a step in the same workflow execution, as this can lead to deadlocks.
</Note>
For example:
```ts title="src/workflows/steps/charge-customer.ts"
import { createStep } from "@medusajs/framework/workflows-sdk"
type StepInput = {
order_id: string
customer_id: string
}
export const chargeCustomerStep = createStep(
"charge-customer",
async (input: StepInput, { container }) => {
const lockingModuleService = container.resolve("locking")
await lockingModuleService.acquire(input.order_id, {
// Lock will auto-expire after 10 seconds
expire: 10,
})
// TODO: charge customer
await lockingModuleService.release(input.order_id)
}
)
```
In this example, the `chargeCustomerStep` step acquires a lock on the order using the `order_id` as the lock key. After performing the operation, it releases the lock.
<Note title="Tip">
The step will wait until the lock is acquired based on the configured Locking Module Provider's options. For example, the [Redis Locking Module Provider](!resources!/infrastructure-modules/locking/redis) will wait five seconds before timing out.
</Note>
### Locking Module Service API
Refer to the [Locking Module reference](!resources!/references/locking-service) for more information on the Locking Module's service methods.

View File

@@ -4,21 +4,23 @@ export const metadata = {
# {metadata.title}
In this chapter, youll learn how to configure steps to allow retrial on failure.
In this chapter, youll learn how to configure steps to allow retry on failure.
## What is a Step Retrial?
## What is a Step Retry?
A step retrial is a mechanism that allows a step to be retried automatically when it fails. This is useful for handling transient errors, such as network issues or temporary unavailability of a service.
A step retry is a mechanism that allows a step to be retried automatically when it fails. This is useful for handling transient errors, such as network issues or temporary unavailability of a service.
When a step fails, the workflow engine can automatically retry the step a specified number of times before marking the workflow as failed. This can help improve the reliability and resilience of your workflows.
By default, when a step fails, the workflow execution stops, and the workflow is marked as failed. However, you can configure a step to retry on failure.
You can also configure the interval between retries, allowing you to wait for a certain period before attempting the step again. This is useful when the failure is due to a temporary issue that may resolve itself after some time.
When a step fails, you can configure the workflow engine to automatically retry the step a specified number of times before marking the workflow as failed. This can help improve the reliability and resilience of your workflows.
For example, if a step captures a payment, you may want to retry it the next day until the payment is successful or the maximum number of retries is reached.
You can also configure the interval between retries, awllowing you to wait for a certain period before attempting the step again. This is useful when the failure is due to a temporary issue that may resolve itself after some time.
For example, if a step captures a payment, you may want to retry it daily until the payment is successful or the maximum number of retries is reached.
---
## Configure a Steps Retrial
## Configure a Steps Retry
By default, when an error occurs in a step, the step and the workflow fail, and the execution stops.
@@ -72,6 +74,37 @@ Error: Oops! Something happened.
The first line indicates the first time the step was executed, and the next two lines indicate the times the step was retried. After that, the step and workflow fail.
### Disable Automatic Retries
By default, a step configured with the `maxRetries` property will be retried automatically when it fails.
You can disable automatic retries by setting the `autoRetry` property to `false` in the step's configuration object. Then, when the step fails, its status will be set to temporary failure, and you'll need to manually retry it using the [Workflow Engine Module Service](!resources!/infrastructure-modules/workflow-engine).
<Note>
The `autoRetry` property is available since [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2).
</Note>
For example, to disable automatic retries:
```ts title="src/workflows/hello-world.ts" highlights={[["5"]]}
const step1 = createStep(
{
name: "step-1",
maxRetries: 2,
autoRetry: false, // Disable automatic retries
},
async () => {
console.log("Executing step 1")
throw new Error("Oops! Something happened.")
}
)
```
This step will not be retried automatically when it fails. Instead, you'll need to manually retry it, as explained in the [Manually Retry a Step](#manually-retry-a-step) section.
---
## Step Retry Intervals
@@ -88,7 +121,9 @@ const step1 = createStep(
retryInterval: 2, // 2 seconds
},
async () => {
// ...
console.log("Executing step 1")
throw new Error("Oops! Something happened.")
}
)
```
@@ -109,7 +144,9 @@ const step1 = createStep(
retryInterval: 86400, // 1 day
},
async () => {
// ...
console.log("Executing step 1")
throw new Error("Oops! Something happened.")
}
)
```
@@ -122,4 +159,56 @@ By setting `retryInterval` on a step, a workflow that uses that step becomes a [
However, since the long-running workflow runs in the background, you won't receive its result or errors immediately when you execute the workflow.
Instead, you must subscribe to the workflow's execution using the Workflow Engine Module Service. Learn more about it in [this chapter](../long-running-workflow/page.mdx#access-long-running-workflow-status-and-result).
Instead, you must subscribe to the workflow's execution using the Workflow Engine Module's service. Learn more about this in the [Long-Running Workflows](../long-running-workflow/page.mdx#access-long-running-workflow-status-and-result) chapter.
---
## Manually Retry a Step
In some cases, you may need to manually retry a step. For example:
- If a step's `autoRetry` property is set to `false`.
- If the machine running the Medusa application in development or [worker mode](../../../configurations/medusa-config/page.mdx#workermode) dies or shuts down.
- If the step takes longer than expected to complete.
To retry a step manually, resolve the Workflow Engine Module's service from the Medusa container and call its `retryStep` method.
<Note>
The `retryStep` method is available since [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2).
</Note>
For example, to do it in an API route:
export const retryHighlights = [
["8", "workflowEngine", "Resolve the Workflow Engine Module's service from the Medusa container."],
["10", "retryStep", "Retry the step."],
]
```ts title="src/api/retry-step/route.ts" highlights={retryHighlights}
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { TransactionHandlerType } from "@medusajs/framework/utils"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
const workflowEngine = req.scope.resolve("workflows")
workflowEngine.retryStep({
idempotencyKey: {
action: TransactionHandlerType.INVOKE,
transactionId: req.validatedQuery.transaction_id as string,
stepId: "step-1",
workflowId: "hello-world",
},
})
res.json({ message: "Step retry initiated" })
}
```
When you send a request to the API route, the workflow execution will resume, retrying the specified step.
Learn more about the `retryStep` method in the [Workflow Engine Module Service reference](!resources!/infrastructure-modules/workflow-engine/how-to-use#retryStep).

View File

@@ -4,7 +4,7 @@ export const generatedEditDates = {
"app/learn/deployment/page.mdx": "2025-07-18T15:25:33.249Z",
"app/learn/page.mdx": "2025-06-27T11:39:15.941Z",
"app/learn/fundamentals/modules/commerce-modules/page.mdx": "2025-04-17T08:51:32.723Z",
"app/learn/fundamentals/workflows/retry-failed-steps/page.mdx": "2025-03-28T07:15:19.388Z",
"app/learn/fundamentals/workflows/retry-failed-steps/page.mdx": "2025-09-15T09:38:18.299Z",
"app/learn/fundamentals/workflows/workflow-hooks/page.mdx": "2024-12-09T10:44:33.781Z",
"app/learn/debugging-and-testing/logging/page.mdx": "2025-08-28T15:31:57.879Z",
"app/learn/storefront-development/page.mdx": "2024-12-10T09:11:04.993Z",
@@ -121,7 +121,7 @@ export const generatedEditDates = {
"app/learn/fundamentals/workflows/errors/page.mdx": "2025-04-25T14:26:25.000Z",
"app/learn/fundamentals/api-routes/override/page.mdx": "2025-05-09T08:01:24.493Z",
"app/learn/fundamentals/module-links/index/page.mdx": "2025-05-23T07:57:58.958Z",
"app/learn/fundamentals/module-links/index-module/page.mdx": "2025-06-19T16:02:05.665Z",
"app/learn/fundamentals/module-links/index-module/page.mdx": "2025-09-15T07:36:55.853Z",
"app/learn/introduction/build-with-llms-ai/page.mdx": "2025-07-22T16:19:11.668Z",
"app/learn/installation/docker/page.mdx": "2025-07-23T15:34:18.530Z",
"app/learn/fundamentals/generated-types/page.mdx": "2025-07-25T13:17:35.319Z",
@@ -131,5 +131,6 @@ export const generatedEditDates = {
"app/learn/debugging-and-testing/logging/custom-logger/page.mdx": "2025-08-28T15:37:07.328Z",
"app/learn/fundamentals/scheduled-jobs/interval/page.mdx": "2025-09-02T08:36:12.714Z",
"app/learn/debugging-and-testing/feature-flags/create/page.mdx": "2025-09-02T08:36:12.714Z",
"app/learn/debugging-and-testing/feature-flags/page.mdx": "2025-09-02T08:36:12.714Z"
"app/learn/debugging-and-testing/feature-flags/page.mdx": "2025-09-02T08:36:12.714Z",
"app/learn/fundamentals/workflows/locks/page.mdx": "2025-09-15T09:37:00.808Z"
}

View File

@@ -855,6 +855,16 @@ export const generatedSidebars = [
"chapterTitle": "3.7.14. Multiple Step Usage",
"number": "3.7.14."
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/learn/fundamentals/workflows/locks",
"title": "Using Locks",
"children": [],
"chapterTitle": "3.7.15. Using Locks",
"number": "3.7.15."
},
{
"loaded": true,
"isPathHref": true,
@@ -862,8 +872,8 @@ export const generatedSidebars = [
"path": "/learn/debugging-and-testing/debug-workflows",
"title": "Debug Workflows",
"children": [],
"chapterTitle": "3.7.15. Debug Workflows",
"number": "3.7.15."
"chapterTitle": "3.7.16. Debug Workflows",
"number": "3.7.16."
}
],
"chapterTitle": "3.7. Workflows",

View File

@@ -13224,28 +13224,21 @@ The Index Module is experimental and still in development, so it is subject to c
## What is the Index Module?
The Index Module is a tool to perform highly performant queries across modules, for example, to filter linked modules.
The Index Module is a tool to perform high-performance queries across modules, for example, to filter linked modules.
While modules share the same database by default, Medusa [isolates modules](https://docs.medusajs.com/learn/fundamentals/modules/isolation/index.html.md) to allow using external data sources or different database types.
So, when you retrieve data across modules using Query, Medusa aggregates the data coming from different modules to create the end result. This approach limits your ability to filter data by linked modules. For example, you can't filter products (created in the Product Module) by their brand (created in the Brand Module).
The Index Module solves this problem by ingesting data into a central data store on application startup. The data store has a relational structure that enables efficiently filtering data ingested from different modules (and their data stores). So, when you retrieve data with the Index Module, you're retrieving it from the Index' data store, not the original data source.
The Index Module solves this problem by ingesting data into a central data store on application startup. The data store has a relational structure that enables efficient filtering of data ingested from different modules (and their data stores). So, when you retrieve data with the Index Module, you're retrieving it from the Index Module's data store, not the original data source.
![Diagram showcasing how data is retrieved from the Index Module's data store](https://res.cloudinary.com/dza7lstvk/image/upload/v1747988533/Medusa%20Book/index-module_epurmt.jpg)
### Ingested Data Models
Currently, only the following core data models are ingested into Index when you install it:
All core data models in Medusa are ingested, including `Product`, `Price`, `SalesChannel`, and more. You can also index custom data models if they are linked to an ingested data model. You'll learn more about this in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section.
- `Product`
- `ProductVariant`
- `Price`
- `SalesChannel`
Consequently, you can only index custom data models if they are linked to an ingested data model. You'll learn more about this in the [Ingest Custom Data Models](#how-to-ingest-custom-data-models) section.
Future versions may add more data models to the list.
Prior to [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2), only the `Product`, `ProductVariant`, `Price`, and `SalesChannel` data models were ingested. Make sure to update to the latest version to ingest all core data models.
***
@@ -13277,7 +13270,7 @@ Finally, run the migrations to create the necessary tables for the Index Module
npx medusa db:migrate
```
The index module only ingests data when you start your Medusa server. So, to ingest the [currently supported data models](#ingested-data-models), start the Medusa application:
The Index Module only ingests data when you start your Medusa server. So, to ingest the [currently supported data models](#ingested-data-models), start the Medusa application:
```bash npm2yarn
npm run dev
@@ -19742,6 +19735,117 @@ So, the parent workflow will wait for the nested workflow to finish before conti
Refer to the [Long-Running Workflows](https://docs.medusajs.com/learn/fundamentals/workflows/long-running-workflow/index.html.md) chapter for more information on how to handle long-running workflows.
# Locking Operations in Workflows
In this chapter, youll learn how to lock operations in your workflows to avoid race conditions and ensure data consistency.
## What is a Lock?
A lock is a mechanism that restricts multiple accesses to a resource or a piece of code, preventing multiple processes from modifying it simultaneously.
Locks are particularly useful in workflows where concurrent executions may lead to commerce risks. For example, Medusa uses locks in its cart workflows to prevent issues like overselling products or double charging customers.
The [Locking Module](https://docs.medusajs.com/resources/infrastructure-modules/locking/index.html.md) handles the locking mechanism using the underlying provider. You can use the Locking Module's service in your workflows to create locks around critical sections of your code.
***
## How to Use Locks in Workflows
Medusa provides two steps that you can use to create locks in your workflows:
- `acquireLockStep`: Attempt to acquire a lock. If the lock is already held by another process, this step will wait until the lock is released. It will fail if a timeout occurs before acquiring the lock.
- `releaseLockStep`: Release a previously acquired lock.
You can use these steps in your workflows to ensure that only one instance of a workflow can modify a resource at a time.
For example:
```ts title="src/workflows/charge-customer.ts" highlights={workflowLockHighlights}
import { createWorkflow } from "@medusajs/framework/workflows-sdk"
import { acquireLockStep, releaseLockStep } from "@medusajs/medusa/core-flows"
import { chargeCustomerStep } from "./steps/charge-customer-step"
type WorkflowInput = {
customer_id: string;
order_id: string;
}
export const chargeCustomerWorkflow = createWorkflow(
"charge-customer",
(input: WorkflowInput) => {
acquireLockStep({
key: input.order_id,
// Attempt to acquire the lock for two seconds before timing out
timeout: 2,
// Lock is only held for a maximum of ten seconds
ttl: 10,
})
chargeCustomerStep(input)
releaseLockStep({
key: input.order_id,
})
}
)
```
In this example, the workflow attempts to acquire a lock on an order using its ID as the lock key.
Once the lock is acquired, it executes the `chargeCustomerStep`. After the step is complete, it releases the lock using the `releaseLockStep`.
If the lock cannot be acquired within the specified timeout period, the `acquireLockStep` will throw an error, and the workflow will fail.
If an error occurs in the workflow after a lock is acquired with `acquireLockStep`, the step's compensation function will release the lock automatically.
### Locking Steps API
Refer to the [acquireLockStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/acquireLockStep/index.html.md) and [releaseLockStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/releaseLockStep/index.html.md) for more information on the inputs of these steps.
***
## How to Use Locks in Workflow Steps
You can alternatively acquire and release locks within steps by resolving the Locking Module's service and using its `acquire` and `release` methods.
Do not acquire locks within a workflow and a step in the same workflow execution, as this can lead to deadlocks.
For example:
```ts title="src/workflows/steps/charge-customer.ts"
import { createStep } from "@medusajs/framework/workflows-sdk"
type StepInput = {
order_id: string
customer_id: string
}
export const chargeCustomerStep = createStep(
"charge-customer",
async (input: StepInput, { container }) => {
const lockingModuleService = container.resolve("locking")
await lockingModuleService.acquire(input.order_id, {
// Lock will auto-expire after 10 seconds
expire: 10,
})
// TODO: charge customer
await lockingModuleService.release(input.order_id)
}
)
```
In this example, the `chargeCustomerStep` step acquires a lock on the order using the `order_id` as the lock key. After performing the operation, it releases the lock.
The step will wait until the lock is acquired based on the configured Locking Module Provider's options. For example, the [Redis Locking Module Provider](https://docs.medusajs.com/resources/infrastructure-modules/locking/redis/index.html.md) will wait five seconds before timing out.
### Locking Module Service API
Refer to the [Locking Module reference](https://docs.medusajs.com/resources/references/locking-service/index.html.md) for more information on the Locking Module's service methods.
# Long-Running Workflows
In this chapter, youll learn what a long-running workflow is and how to configure it.
@@ -20412,21 +20516,23 @@ So, `prices` is the result of `createPricesStep`, and `productSalesChannel` is t
# Retry Failed Steps
In this chapter, youll learn how to configure steps to allow retrial on failure.
In this chapter, youll learn how to configure steps to allow retry on failure.
## What is a Step Retrial?
## What is a Step Retry?
A step retrial is a mechanism that allows a step to be retried automatically when it fails. This is useful for handling transient errors, such as network issues or temporary unavailability of a service.
A step retry is a mechanism that allows a step to be retried automatically when it fails. This is useful for handling transient errors, such as network issues or temporary unavailability of a service.
When a step fails, the workflow engine can automatically retry the step a specified number of times before marking the workflow as failed. This can help improve the reliability and resilience of your workflows.
By default, when a step fails, the workflow execution stops, and the workflow is marked as failed. However, you can configure a step to retry on failure.
You can also configure the interval between retries, allowing you to wait for a certain period before attempting the step again. This is useful when the failure is due to a temporary issue that may resolve itself after some time.
When a step fails, you can configure the workflow engine to automatically retry the step a specified number of times before marking the workflow as failed. This can help improve the reliability and resilience of your workflows.
For example, if a step captures a payment, you may want to retry it the next day until the payment is successful or the maximum number of retries is reached.
You can also configure the interval between retries, awllowing you to wait for a certain period before attempting the step again. This is useful when the failure is due to a temporary issue that may resolve itself after some time.
For example, if a step captures a payment, you may want to retry it daily until the payment is successful or the maximum number of retries is reached.
***
## Configure a Steps Retrial
## Configure a Steps Retry
By default, when an error occurs in a step, the step and the workflow fail, and the execution stops.
@@ -20480,6 +20586,33 @@ Error: Oops! Something happened.
The first line indicates the first time the step was executed, and the next two lines indicate the times the step was retried. After that, the step and workflow fail.
### Disable Automatic Retries
By default, a step configured with the `maxRetries` property will be retried automatically when it fails.
You can disable automatic retries by setting the `autoRetry` property to `false` in the step's configuration object. Then, when the step fails, its status will be set to temporary failure, and you'll need to manually retry it using the [Workflow Engine Module Service](https://docs.medusajs.com/resources/infrastructure-modules/workflow-engine/index.html.md).
The `autoRetry` property is available since [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2).
For example, to disable automatic retries:
```ts title="src/workflows/hello-world.ts" highlights={[["5"]]}
const step1 = createStep(
{
name: "step-1",
maxRetries: 2,
autoRetry: false, // Disable automatic retries
},
async () => {
console.log("Executing step 1")
throw new Error("Oops! Something happened.")
}
)
```
This step will not be retried automatically when it fails. Instead, you'll need to manually retry it, as explained in the [Manually Retry a Step](#manually-retry-a-step) section.
***
## Step Retry Intervals
@@ -20496,7 +20629,9 @@ const step1 = createStep(
retryInterval: 2, // 2 seconds
},
async () => {
// ...
console.log("Executing step 1")
throw new Error("Oops! Something happened.")
}
)
```
@@ -20517,7 +20652,9 @@ const step1 = createStep(
retryInterval: 86400, // 1 day
},
async () => {
// ...
console.log("Executing step 1")
throw new Error("Oops! Something happened.")
}
)
```
@@ -20530,7 +20667,50 @@ By setting `retryInterval` on a step, a workflow that uses that step becomes a [
However, since the long-running workflow runs in the background, you won't receive its result or errors immediately when you execute the workflow.
Instead, you must subscribe to the workflow's execution using the Workflow Engine Module Service. Learn more about it in [this chapter](https://docs.medusajs.com/learn/fundamentals/workflows/long-running-workflow#access-long-running-workflow-status-and-result/index.html.md).
Instead, you must subscribe to the workflow's execution using the Workflow Engine Module's service. Learn more about this in the [Long-Running Workflows](https://docs.medusajs.com/learn/fundamentals/workflows/long-running-workflow#access-long-running-workflow-status-and-result/index.html.md) chapter.
***
## Manually Retry a Step
In some cases, you may need to manually retry a step. For example:
- If a step's `autoRetry` property is set to `false`.
- If the machine running the Medusa application in development or [worker mode](https://docs.medusajs.com/learn/configurations/medusa-config#workermode/index.html.md) dies or shuts down.
- If the step takes longer than expected to complete.
To retry a step manually, resolve the Workflow Engine Module's service from the Medusa container and call its `retryStep` method.
The `retryStep` method is available since [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2).
For example, to do it in an API route:
```ts title="src/api/retry-step/route.ts" highlights={retryHighlights}
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
import { TransactionHandlerType } from "@medusajs/framework/utils"
export async function GET(
req: MedusaRequest,
res: MedusaResponse
) {
const workflowEngine = req.scope.resolve("workflows")
workflowEngine.retryStep({
idempotencyKey: {
action: TransactionHandlerType.INVOKE,
transactionId: req.validatedQuery.transaction_id as string,
stepId: "step-1",
workflowId: "hello-world",
},
})
res.json({ message: "Step retry initiated" })
}
```
When you send a request to the API route, the workflow execution will resume, retrying the specified step.
Learn more about the `retryStep` method in the [Workflow Engine Module Service reference](https://docs.medusajs.com/resources/infrastructure-modules/workflow-engine/how-to-use#retryStep/index.html.md).
# Store Workflow Executions
@@ -41200,6 +41380,47 @@ You can then use the Workflow Engine Module's service's methods in the step. The
***
## retryStep
This method retries a step that has temporary failed, such as a step that has `autoRetry` set to `false` or when the machine running the Medusa application shuts down. Learn more about it in the [Retry Failed Steps](https://docs.medusajs.com/docs/learn/fundamentals/workflows/retry-failed-steps/index.html.md) guide.
This method is available since [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2).
### Example
```ts
// other imports...
import {
TransactionHandlerType,
} from "@medusajs/framework/utils"
workflowEngine.retryStep({
idempotencyKey: {
action: TransactionHandlerType.INVOKE,
transactionId,
stepId: "step-1",
workflowId: "hello-world",
},
})
```
### Parameters
- idempotencyKey: (\`object\`) The details of the step to retry.
- action: (\`invoke\` | \`compensate\`) If the step's compensation function is running, use \`compensate\`. Otherwise, use \`invoke\`.
- transactionId: (\`string\`) The ID of the workflow execution's transaction.
- stepId: (\`string\`) The ID of the step to change its status. This is the first parameter passed to \`createStep\` when creating the step.
- workflowId: (\`string\`) The ID of the workflow. This is the first parameter passed to \`createWorkflow\` when creating the workflow.
- options: (\`object\`) Options to pass to the step.
- container: (\`Container\`) An instance of the Medusa container.
***
## setStepSuccess
This method sets an async step in a currently-executing [long-running workflow](https://docs.medusajs.com/docs/learn/fundamentals/workflows/long-running-workflow/index.html.md) as successful. The workflow will then continue to the next step.
@@ -41220,9 +41441,6 @@ await workflowEngineModuleService.setStepSuccess({
workflowId: "hello-world",
},
stepResponse: new StepResponse("Done!"),
options: {
container,
},
})
```
@@ -41264,9 +41482,6 @@ await workflowEngineModuleService.setStepFailure({
workflowId: "hello-world",
},
stepResponse: new StepResponse("Failed!"),
options: {
container,
},
})
```
@@ -97914,6 +98129,7 @@ This component adds a filter menu to the data table, allowing users
to filter the table's data.
- tooltip: (string) The tooltip to show when hovering over the filter menu.
- onAddFilter: (signature) Callback when a filter is added
### DataTable.Search Props

View File

@@ -448,6 +448,11 @@ export const sidebars = [
path: "/learn/fundamentals/workflows/multiple-step-usage",
title: "Multiple Step Usage",
},
{
type: "link",
path: "/learn/fundamentals/workflows/locks",
title: "Using Locks",
},
{
type: "ref",
path: "/learn/debugging-and-testing/debug-workflows",

View File

@@ -44,6 +44,106 @@ You can then use the Workflow Engine Module's service's methods in the step. The
---
## retryStep
This method retries a step that has temporary failed, such as a step that has `autoRetry` set to `false` or when the machine running the Medusa application shuts down. Learn more about it in the [Retry Failed Steps](!docs!/learn/fundamentals/workflows/retry-failed-steps) guide.
<Note>
This method is available since [Medusa v2.10.2](https://github.com/medusajs/medusa/releases/tag/v2.10.2).
</Note>
### Example
```ts
// other imports...
import {
TransactionHandlerType,
} from "@medusajs/framework/utils"
workflowEngine.retryStep({
idempotencyKey: {
action: TransactionHandlerType.INVOKE,
transactionId,
stepId: "step-1",
workflowId: "hello-world",
},
})
```
### Parameters
<TypeList types={[
{
"name": "idempotencyKey",
"type": "`object`",
"description": "The details of the step to retry.",
"optional": false,
"defaultValue": "",
"expandable": false,
"children": [
{
"name": "action",
"type": "`invoke` | `compensate`",
"description": "If the step's compensation function is running, use `compensate`. Otherwise, use `invoke`.",
"optional": false,
"defaultValue": "",
"expandable": false,
"children": []
},
{
"name": "transactionId",
"type": "`string`",
"description": "The ID of the workflow execution's transaction.",
"optional": false,
"defaultValue": "",
"expandable": false,
"children": []
},
{
"name": "stepId",
"type": "`string`",
"description": "The ID of the step to change its status. This is the first parameter passed to `createStep` when creating the step.",
"optional": false,
"defaultValue": "",
"expandable": false,
"children": []
},
{
"name": "workflowId",
"type": "`string`",
"description": "The ID of the workflow. This is the first parameter passed to `createWorkflow` when creating the workflow.",
"optional": false,
"defaultValue": "",
"expandable": false,
"children": []
}
]
},
{
"name": "options",
"type": "`object`",
"description": "Options to pass to the step.",
"optional": true,
"defaultValue": "",
"expandable": false,
"children": [
{
"name": "container",
"type": "`Container`",
"description": "An instance of the Medusa container.",
"optional": false,
"defaultValue": "",
"expandable": false,
"children": []
}
]
}
]} expandUrl="https://docs.medusajs.com/learn/fundamentals/data-models/manage-relationships#retrieve-records-of-relation" sectionTitle="retryStep"/>
---
## setStepSuccess
This method sets an async step in a currently-executing [long-running workflow](!docs!/learn/fundamentals/workflows/long-running-workflow) as successful. The workflow will then continue to the next step.
@@ -64,9 +164,6 @@ await workflowEngineModuleService.setStepSuccess({
workflowId: "hello-world",
},
stepResponse: new StepResponse("Done!"),
options: {
container,
},
})
```
@@ -132,7 +229,7 @@ await workflowEngineModuleService.setStepSuccess({
"name": "options",
"type": "`object`",
"description": "Options to pass to the step.",
"optional": false,
"optional": true,
"defaultValue": "",
"expandable": false,
"children": [
@@ -171,9 +268,6 @@ await workflowEngineModuleService.setStepFailure({
workflowId: "hello-world",
},
stepResponse: new StepResponse("Failed!"),
options: {
container,
},
})
```
@@ -239,7 +333,7 @@ await workflowEngineModuleService.setStepFailure({
"name": "options",
"type": "`object`",
"description": "Options to pass to the step.",
"optional": false,
"optional": true,
"defaultValue": "",
"expandable": false,
"children": [

View File

@@ -6123,7 +6123,7 @@ export const generatedEditDates = {
"references/tax/types/tax.Message/page.mdx": "2025-04-11T09:04:52.576Z",
"references/types/interfaces/types.IFulfillmentProvider/page.mdx": "2025-05-20T07:51:41.084Z",
"references/user/types/user.Message/page.mdx": "2025-04-11T09:04:52.767Z",
"app/infrastructure-modules/workflow-engine/how-to-use/page.mdx": "2025-03-27T14:53:13.311Z",
"app/infrastructure-modules/workflow-engine/how-to-use/page.mdx": "2025-09-15T08:06:10.452Z",
"references/core_flows/Notification/Steps_Notification/functions/core_flows.Notification.Steps_Notification.notifyOnFailureStep/page.mdx": "2025-04-23T16:21:19.025Z",
"app/troubleshooting/api-routes/additional-data-error/page.mdx": "2025-03-27T17:39:10.858Z",
"app/troubleshooting/api-routes/middleware-registration/page.mdx": "2025-04-17T10:35:42.095Z",
@@ -6531,6 +6531,8 @@ export const generatedEditDates = {
"references/core_flows/Draft_Order/Steps_Draft_Order/variables/core_flows.Draft_Order.Steps_Draft_Order.deleteDraftOrdersStepId/page.mdx": "2025-06-05T19:05:37.064Z",
"references/core_flows/Draft_Order/Workflows_Draft_Order/functions/core_flows.Draft_Order.Workflows_Draft_Order.deleteDraftOrdersWorkflow/page.mdx": "2025-09-15T09:52:13.890Z",
"references/core_flows/Draft_Order/Workflows_Draft_Order/variables/core_flows.Draft_Order.Workflows_Draft_Order.deleteDraftOrderWorkflowId/page.mdx": "2025-06-05T19:05:37.318Z",
"references/core_flows/Locking/functions/core_flows.Locking.acquireLockStep/page.mdx": "2025-09-15T09:11:26.324Z",
"references/core_flows/Locking/functions/core_flows.Locking.releaseLockStep/page.mdx": "2025-09-15T09:11:38.276Z",
"references/core_flows/core_flows.Locking/page.mdx": "2025-09-15T09:52:14.217Z",
"references/core_flows/interfaces/core_flows.AcquireLockStepInput/page.mdx": "2025-09-15T09:52:15.944Z",
"references/core_flows/interfaces/core_flows.ReleaseLockStepInput/page.mdx": "2025-09-15T09:52:15.945Z",