diff --git a/daprdocs/content/en/developing-applications/building-blocks/workflow/workflow-overview.md b/daprdocs/content/en/developing-applications/building-blocks/workflow/workflow-overview.md
index 67e4941f880..5f34ba20abe 100644
--- a/daprdocs/content/en/developing-applications/building-blocks/workflow/workflow-overview.md
+++ b/daprdocs/content/en/developing-applications/building-blocks/workflow/workflow-overview.md
@@ -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.
diff --git a/daprdocs/content/en/developing-applications/building-blocks/workflow/workflow-patterns.md b/daprdocs/content/en/developing-applications/building-blocks/workflow/workflow-patterns.md
index faa92d946ae..3e307cb5494 100644
--- a/daprdocs/content/en/developing-applications/building-blocks/workflow/workflow-patterns.md
+++ b/daprdocs/content/en/developing-applications/building-blocks/workflow/workflow-patterns.md
@@ -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 >}}
@@ -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:
+
+
+
+This is how cross-app start child workflow looks like:
+
+
+
+### 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.)
+
+
+
+#### 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.
@@ -1428,33 +1508,33 @@ 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 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) {
@@ -1462,24 +1542,24 @@ public class PaymentProcessingWorkflow implements Workflow {
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;
@@ -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);
};
}
@@ -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)
diff --git a/daprdocs/static/images/workflow-overview/workflow-crossapp-callactivity.png b/daprdocs/static/images/workflow-overview/workflow-crossapp-callactivity.png
new file mode 100644
index 00000000000..7b2a28561d8
Binary files /dev/null and b/daprdocs/static/images/workflow-overview/workflow-crossapp-callactivity.png differ
diff --git a/daprdocs/static/images/workflow-overview/workflow-crossapp-sharedpool.png b/daprdocs/static/images/workflow-overview/workflow-crossapp-sharedpool.png
new file mode 100644
index 00000000000..e6ffc9f409b
Binary files /dev/null and b/daprdocs/static/images/workflow-overview/workflow-crossapp-sharedpool.png differ
diff --git a/daprdocs/static/images/workflow-overview/workflow-crossapp-suborchestrator.png b/daprdocs/static/images/workflow-overview/workflow-crossapp-suborchestrator.png
new file mode 100644
index 00000000000..5d5cec79b38
Binary files /dev/null and b/daprdocs/static/images/workflow-overview/workflow-crossapp-suborchestrator.png differ