docs: document locks for nested workflows (#14130)

* docs: document locks for nested workflows

* smal text change

* fix build error
This commit is contained in:
Shahed Nasser authored and GitHub committed 2025-11-26 15:36:58 +02:00
1 parent 76660fb6cc
commit c1ede88a7e
53 files changed
+712 -208

No files matched your search

+85 -28
View File
@@ -22299,8 +22299,8 @@ The [Locking Module](https://docs.medusajs.com/resources/infrastructure-modules/
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.
- [acquireLockStep](https://docs.medusajs.com/resources/references/medusa-workflows/steps/acquireLockStep/index.html.md): 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](https://docs.medusajs.com/resources/references/medusa-workflows/steps/releaseLockStep/index.html.md): 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.
@@ -22391,6 +22391,57 @@ The step will wait until the lock is acquired based on the configured Locking Mo
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.
***
## Locks in Nested Workflows
[Nested workflows](https://docs.medusajs.com/learn/fundamentals/workflows/execute-another-workflow/index.html.md) can't acquire locks. So, if you're using a workflow that acquires locks within another workflow, the parent workflow must handle the locking mechanism.
For example, consider a custom workflow that executes Medusa's [completeCartWorkflow](https://docs.medusajs.com/resources/references/medusa-workflows/completeCartWorkflow/index.html.md). The `completeCartWorkflow` acquires locks on the cart to prevent race conditions.
Therefore, the custom workflow must acquire and release the locks around the `completeCartWorkflow` execution. For example:
```ts title="src/workflows/custom-complete-cart.ts" highlights={nestedWorkflowLockHighlights}
import { createWorkflow } from "@medusajs/framework/workflows-sdk"
import {
acquireLockStep,
releaseLockStep,
completeCartWorkflow
} from "@medusajs/medusa/core-flows"
type WorkflowInput = {
cart_id: string;
}
export const customCompleteCartWorkflow = createWorkflow(
"custom-complete-cart",
(input: WorkflowInput) => {
// acquire the same lock as the nested workflow
acquireLockStep({
key: input.cart_id,
timeout: 30,
ttl: 60 * 2,
})
// Execute the nested workflow
completeCartWorkflow.runAsStep({
input: {
id: input.cart_id,
}
})
// release the lock after the nested workflow is complete
releaseLockStep({
key: input.cart_id,
})
}
)
```
In the example above, the `customCompleteCartWorkflow` acquires a lock on the cart before executing the `completeCartWorkflow` and releases it afterward.
Make sure you're acquiring the same lock key as the nested workflow.
# Long-Running Workflows
@@ -45263,44 +45314,50 @@ For example, Medusa uses the Locking Module in inventory management to ensure th
You can use the Locking Module as part of the [workflows](https://docs.medusajs.com/docs/learn/fundamentals/workflows/index.html.md) you build for your custom features. A workflow is a special function composed of a series of steps that guarantees data consistency and reliable roll-back mechanism.
In a step of your workflow, you can resolve the Locking Module's service and use its methods to execute an asynchronous job, acquire a lock, or release locks.
In a workflow, you can either use:
- Medusa's [acquireLockStep](https://docs.medusajs.com/references/medusa-workflows/steps/acquireLockStep/index.html.md) and [releaseLockStep](https://docs.medusajs.com/references/medusa-workflows/steps/releaseLockStep/index.html.md) to create locks around critical steps in your workflow.
- The Locking Module's service directly in your steps to have more control over the locking mechanism
For example:
```ts
import { Modules } from "@medusajs/framework/utils"
import {
createStep,
createWorkflow,
} from "@medusajs/framework/workflows-sdk"
### Workflow
const step1 = createStep(
"step-1",
async ({}, { container }) => {
const lockingModuleService = container.resolve(
Modules.LOCKING
)
const productModuleService = container.resolve(
Modules.PRODUCT
)
```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"
await lockingModuleService.execute("prod_123", async () => {
await productModuleService.deleteProduct("prod_123")
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,
})
}
)
export const workflow = createWorkflow(
"workflow-1",
() => {
step1()
chargeCustomerStep(input)
releaseLockStep({
key: input.order_id,
})
}
)
```
In the example above, you create a workflow that has a step. In the step, you resolve the services of the Locking and Product modules from the [Medusa container](https://docs.medusajs.com/docs/learn/fundamentals/medusa-container/index.html.md).
In the example above, you create a workflow that acquires a lock on an order using the `acquireLockStep` before charging a customer. The lock is then released using the `releaseLockStep` after the operation is complete.
Then, you use the `execute` method of the Locking Module to acquire a lock for the product with the ID `prod_123` and execute an asynchronous function, which deletes the product.
This ensures that only one instance of the workflow can modify the order at a time, preventing issues like double charging the customer.
### Step
***