Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ Child workflow also supports automatic retry policies.

[Learn more about child workflows.]({{% ref "workflow-features-concepts.md#child-workflows" %}})

### Cross-app workflows

Dapr Workflows support cross-app orchestration, allowing you to call activities and start child workflows in different Dapr applications. This enables distributed workflow execution across your microservice architecture while maintaining the benefits of Dapr's workflow engine.

[Learn more about cross-app workflows.]({{% ref "workflow-patterns.md#cross-app-workflows" %}})

### Timers and reminders

Same as Dapr actors, you can schedule reminder-like durable delays for any time range.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ await context.CallActivityAsync("PostResults", sum);

{{< /tabpane >}}

With the release of 1.16, it's even easier to process workflow activities in parallel while putting an upper cap on
With the release of 1.16, it's even easier to process workflow activities in parallel while putting an upper cap on
concurrency by using the following extension methods on the `WorkflowContext`:

{{< tabpane text=true >}}
Expand Down Expand Up @@ -1385,6 +1385,86 @@ func raiseEvent() {

External events don't have to be directly triggered by humans. They can also be triggered by other systems. For example, a workflow may need to pause and wait for a payment to be received. In this case, a payment system might publish an event to a pub/sub topic on receipt of a payment, and a listener on that topic can raise an event to the workflow using the raise event workflow API.

## Cross-app workflows

The cross-app workflow pattern enables workflows to call activities or start child workflows hosted in different Dapr applications.

{{% alert title="Important Limitations" color="warning" %}}
- **Cross-namespace calls are not supported** - all applications must be in the **same namespace**
- **Only activity calls are supported in Java SDK** - Cross-app workflow activity calls are currently only available in the Java SDK. Child workflow calls are not supported yet. Other SDKs (Python, .NET, JavaScript, Go) do not support any cross-app features at this time.
{{% /alert %}}

This is how cross-app call activity looks like:

<img src="/images/workflow-overview/workflow-crossapp-callactivity.png" width=800 alt="Diagram showing cross-app call activity workflow pattern">

This is how cross-app start child workflow looks like:

<img src="/images/workflow-overview/workflow-crossapp-suborchestrator.png" width=800 alt="Diagram showing cross-app child workflow pattern">

### Use cases and scenarios

Cross-app workflows are ideal for the following scenarios:

#### Shared activity pools

One of the main use cases is creating shared pools of workflow activities and child workflows that can be:
- Called from multiple workflow orchestrators running in different applications
- Scaled independently based on demand for different business functions
- Owned and maintained by different teams
- Specialized for specific business functions (e.g., payment processing, inventory management, notifications, etc.)

<img src="/images/workflow-overview/workflow-crossapp-sharedpool.png" width=800 alt="Diagram showing cross-app shared pool workflow pattern">

#### Team boundaries and microservice ownership
Cross-app workflows enable different teams to own different parts of a larger business process:
- **Team A** owns the orchestration logic
- **Team B** owns payment activities
- **Team C** owns inventory activities
- **Team D** owns shipping activities

Each team can deploy, scale, and maintain their applications containing workflows and activities independently while participating in larger orchestrated workflows.

### Error handling

When calling cross-app activities or child workflows:
- If the target application does not exist, the call will be retried using the provided retry policy
- If the target application exists but doesn't contain the specified activity or workflow, the call will return an error
- Standard workflow retry policies apply to cross-app calls

### Cross-app activity calls

You can call activities hosted in different Dapr applications by providing the App ID when calling the activity.

At the moment this is only supported in the Java SDK.

```java
public class MyWorkflow implements Workflow {
@Override
public WorkflowStub create() {
return ctx -> {
// Call an activity in a different application
String result = ctx.callActivity(
"ActivityName", // Activity name
"input data", // Input data
new WorkflowTaskOptions("appId"), // Target application ID
String.class // Return type
).await();
ctx.complete(result);
};
}
}

```

### Cross-app child workflow calls

You can call child workflows hosted in different Dapr applications by providing the App ID when calling the child workflow.

{{% alert title="Not Yet Supported" color="info" %}}
Cross-app child workflow calls are not supported yet in any SDK. This functionality is planned for future releases.
{{% /alert %}}

## Compensation

The compensation pattern (also known as the saga pattern) provides a mechanism for rolling back or undoing operations that have already been executed when a workflow fails partway through. This pattern is particularly important for long-running workflows that span multiple microservices where traditional database transactions are not feasible.
Expand Down Expand Up @@ -1428,58 +1508,58 @@ The following diagram illustrates this flow.

```java
public class PaymentProcessingWorkflow implements Workflow {

@Override
public WorkflowStub create() {
return ctx -> {
ctx.getLogger().info("Starting Workflow: " + ctx.getName());
var orderId = ctx.getInput(String.class);
List<String> compensations = new ArrayList<>();

try {
// Step 1: Reserve inventory
String reservationId = ctx.callActivity(ReserveInventoryActivity.class.getName(), orderId, String.class).await();
ctx.getLogger().info("Inventory reserved: {}", reservationId);
compensations.add("ReleaseInventory");

// Step 2: Process payment
String paymentId = ctx.callActivity(ProcessPaymentActivity.class.getName(), orderId, String.class).await();
ctx.getLogger().info("Payment processed: {}", paymentId);
compensations.add("RefundPayment");

// Step 3: Ship order
String shipmentId = ctx.callActivity(ShipOrderActivity.class.getName(), orderId, String.class).await();
ctx.getLogger().info("Order shipped: {}", shipmentId);
compensations.add("CancelShipment");

} catch (TaskFailedException e) {
ctx.getLogger().error("Activity failed: {}", e.getMessage());

// Execute compensations in reverse order
Collections.reverse(compensations);
for (String compensation : compensations) {
try {
switch (compensation) {
case "CancelShipment":
String shipmentCancelResult = ctx.callActivity(
CancelShipmentActivity.class.getName(),
orderId,
CancelShipmentActivity.class.getName(),
orderId,
String.class).await();
ctx.getLogger().info("Shipment cancellation completed: {}", shipmentCancelResult);
break;

case "RefundPayment":
String refundResult = ctx.callActivity(
RefundPaymentActivity.class.getName(),
orderId,
RefundPaymentActivity.class.getName(),
orderId,
String.class).await();
ctx.getLogger().info("Payment refund completed: {}", refundResult);
break;

case "ReleaseInventory":
String releaseResult = ctx.callActivity(
ReleaseInventoryActivity.class.getName(),
orderId,
ReleaseInventoryActivity.class.getName(),
orderId,
String.class).await();
ctx.getLogger().info("Inventory release completed: {}", releaseResult);
break;
Expand All @@ -1494,7 +1574,7 @@ public class PaymentProcessingWorkflow implements Workflow {
// Step 4: Send confirmation
ctx.callActivity(SendConfirmationActivity.class.getName(), orderId, Void.class).await();
ctx.getLogger().info("Confirmation sent for order: {}", orderId);

ctx.complete("Order processed successfully: " + orderId);
};
}
Expand Down Expand Up @@ -1597,7 +1677,7 @@ The compensation pattern ensures that your distributed workflows can maintain co
- [Try out Dapr Workflows using the quickstart]({{% ref workflow-quickstart.md %}})
- [Workflow overview]({{% ref workflow-overview.md %}})
- [Workflow API reference]({{% ref workflow_api.md %}})
- Try out the following examples:
- Try out the following examples:
- [Python](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow)
- [JavaScript](https://github.com/dapr/js-sdk/tree/main/examples/workflow)
- [.NET](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading