Skip to content
Merged
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
52 changes: 26 additions & 26 deletions examples/src/main/java/io/dapr/examples/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Those examples contain the following workflow patterns:
4. [External Event Pattern](#external-event-pattern)
5. [Child-workflow Pattern](#child-workflow-pattern)
6. [Compensation Pattern](#compensation-pattern)
7. [Cross-App Pattern](#cross-app-pattern)
7. [Multi-App Pattern](#multi-app-pattern)

### Chaining Pattern
In the chaining pattern, a sequence of activities executes in a specific order.
Expand Down Expand Up @@ -682,49 +682,49 @@ Key Points:
4. Each activity simulates work with a short delay for demonstration purposes


### Cross-App Pattern
### Multi-App Pattern

The cross-app pattern allows workflows to call activities that are hosted in different Dapr applications. This is useful for microservices architectures allowing multiple applications to host activities that can be orchestrated by Dapr Workflows.
The multi-app pattern allows workflows to call activities that are hosted in different Dapr applications. This is useful for microservices architectures allowing multiple applications to host activities that can be orchestrated by Dapr Workflows.

The `CrossAppWorkflow` class defines the workflow. It demonstrates calling activities in different apps using the `appId` parameter in `WorkflowTaskOptions`. See the code snippet below:
The `MultiAppWorkflow` class defines the workflow. It demonstrates calling activities in different apps using the `appId` parameter in `WorkflowTaskOptions`. See the code snippet below:
```java
public class CrossAppWorkflow implements Workflow {
public class MultiAppWorkflow implements Workflow {
@Override
public WorkflowStub create() {
return ctx -> {
var logger = ctx.getLogger();
logger.info("=== WORKFLOW STARTING ===");
logger.info("Starting CrossAppWorkflow: {}", ctx.getName());
logger.info("Starting MultiAppWorkflow: {}", ctx.getName());
logger.info("Workflow name: {}", ctx.getName());
logger.info("Workflow instance ID: {}", ctx.getInstanceId());

String input = ctx.getInput(String.class);
logger.info("CrossAppWorkflow received input: {}", input);
logger.info("MultiAppWorkflow received input: {}", input);
logger.info("Workflow input: {}", input);

// Call an activity in another app by passing in an active appID to the WorkflowTaskOptions
logger.info("Calling cross-app activity in 'app2'...");
logger.info("About to call cross-app activity in app2...");
String crossAppResult = ctx.callActivity(
logger.info("Calling multi-app activity in 'app2'...");
logger.info("About to call multi-app activity in app2...");
String multiAppResult = ctx.callActivity(
App2TransformActivity.class.getName(),
input,
new WorkflowTaskOptions("app2"),
String.class
).await();

// Call another activity in a different app
logger.info("Calling cross-app activity in 'app3'...");
logger.info("About to call cross-app activity in app3...");
logger.info("Calling multi-app activity in 'app3'...");
logger.info("About to call multi-app activity in app3...");
String finalResult = ctx.callActivity(
App3FinalizeActivity.class.getName(),
crossAppResult,
multiAppResult,
new WorkflowTaskOptions("app3"),
String.class
).await();
logger.info("Final cross-app activity result: {}", finalResult);
logger.info("Final cross-app activity result: {}", finalResult);
logger.info("Final multi-app activity result: {}", finalResult);
logger.info("Final multi-app activity result: {}", finalResult);

logger.info("CrossAppWorkflow finished with: {}", finalResult);
logger.info("MultiAppWorkflow finished with: {}", finalResult);
logger.info("=== WORKFLOW COMPLETING WITH: {} ===" , finalResult);
ctx.complete(finalResult);
};
Expand Down Expand Up @@ -784,31 +784,31 @@ public class App3FinalizeActivity implements WorkflowActivity {

**Important Limitations:**
- **Cross-app calls are currently supported for activities only**
- **Child workflow cross-app calls (suborchestration) are NOT supported**
- **Child workflow multi-app calls (suborchestration) are NOT supported**
- The app ID must match the Dapr application ID of the target service

**Running the Cross-App Example:**

This example requires running multiple Dapr applications simultaneously. You'll need to run the following commands in separate terminals:

1. **Start the main workflow worker (crossapp-worker):**
1. **Start the main workflow worker (multiapp-worker):**
```sh
dapr run --app-id crossapp-worker --resources-path ./components/workflows --dapr-grpc-port 50001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.crossapp.CrossAppWorker
dapr run --app-id multiapp-worker --resources-path ./components/workflows --dapr-grpc-port 50001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.MultiAppWorker
```

2. **Start app2 worker (handles App2TransformActivity):**
```sh
dapr run --app-id app2 --resources-path ./components/workflows --dapr-grpc-port 50002 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.crossapp.App2Worker
dapr run --app-id app2 --resources-path ./components/workflows --dapr-grpc-port 50002 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.App2Worker
```

3. **Start app3 worker (handles App3FinalizeActivity):**
```sh
dapr run --app-id app3 --resources-path ./components/workflows --dapr-grpc-port 50003 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.crossapp.App3Worker
dapr run --app-id app3 --resources-path ./components/workflows --dapr-grpc-port 50003 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.App3Worker
```

4. **Run the workflow client:**
```sh
java -Djava.util.logging.ConsoleHandler.level=FINE -Dio.dapr.durabletask.level=FINE -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.crossapp.CrossAppWorkflowClient "Hello World"
java -Djava.util.logging.ConsoleHandler.level=FINE -Dio.dapr.durabletask.level=FINE -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.workflows.multiapp.MultiAppWorkflowClient "Hello World"
```

**Expected Output:**
Expand All @@ -819,15 +819,15 @@ The client will show:
Input: Hello World
Created DaprWorkflowClient successfully
Attempting to start new workflow...
Started a new cross-app workflow with instance ID: 001113f3-b9d9-438c-932a-a9a9b70b9460
Started a new multi-app workflow with instance ID: 001113f3-b9d9-438c-932a-a9a9b70b9460
Waiting for workflow completion...
Workflow instance with ID: 001113f3-b9d9-438c-932a-a9a9b70b9460 completed with result: HELLO WORLD [TRANSFORMED BY APP2] [FINALIZED BY APP3]
```

The workflow demonstrates:
1. The workflow starts in the main worker (crossapp-worker)
2. Calls an activity in 'app2' using cross-app functionality
3. Calls an activity in 'app3' using cross-app functionality
1. The workflow starts in the main worker (multiapp-worker)
2. Calls an activity in 'app2' using multi-app functionality
3. Calls an activity in 'app3' using multi-app functionality
4. The workflow completes with the final result from all activities

This pattern is particularly useful for:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
limitations under the License.
*/

package io.dapr.examples.workflows.crossapp;
package io.dapr.examples.workflows.multiapp;

import io.dapr.workflows.WorkflowActivity;
import io.dapr.workflows.WorkflowActivityContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
limitations under the License.
*/

package io.dapr.examples.workflows.crossapp;
package io.dapr.examples.workflows.multiapp;

import io.dapr.workflows.runtime.WorkflowRuntime;
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
limitations under the License.
*/

package io.dapr.examples.workflows.crossapp;
package io.dapr.examples.workflows.multiapp;

import io.dapr.workflows.WorkflowActivity;
import io.dapr.workflows.WorkflowActivityContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
limitations under the License.
*/

package io.dapr.examples.workflows.crossapp;
package io.dapr.examples.workflows.multiapp;

import io.dapr.workflows.runtime.WorkflowRuntime;
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@
limitations under the License.
*/

package io.dapr.examples.workflows.crossapp;
package io.dapr.examples.workflows.multiapp;

import io.dapr.workflows.runtime.WorkflowRuntime;
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;

public class CrossAppWorker {
public class MultiAppWorker {

public static void main(String[] args) throws Exception {
// Register the Workflow with the builder
WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder()
.registerWorkflow(CrossAppWorkflow.class);
.registerWorkflow(MultiAppWorkflow.class);

// Build and start the workflow runtime
try (WorkflowRuntime runtime = builder.build()) {
System.out.println("CrossAppWorker started - registered CrossAppWorkflow only");
System.out.println("MultiAppWorker started - registered MultiAppWorkflow only");
runtime.start();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
limitations under the License.
*/

package io.dapr.examples.workflows.crossapp;
package io.dapr.examples.workflows.multiapp;

import io.dapr.workflows.Workflow;
import io.dapr.workflows.WorkflowStub;
Expand All @@ -21,42 +21,42 @@
* Example workflow that demonstrates cross-app activity calls.
* This workflow calls activities in different apps using the appId parameter.
*/
public class CrossAppWorkflow implements Workflow {
public class MultiAppWorkflow implements Workflow {
@Override
public WorkflowStub create() {
return ctx -> {
var logger = ctx.getLogger();
logger.info("=== WORKFLOW STARTING ===");
logger.info("Starting CrossAppWorkflow: {}", ctx.getName());
logger.info("Starting MultiAppWorkflow: {}", ctx.getName());
logger.info("Workflow name: {}", ctx.getName());
logger.info("Workflow instance ID: {}", ctx.getInstanceId());

String input = ctx.getInput(String.class);
logger.info("CrossAppWorkflow received input: {}", input);
logger.info("MultiAppWorkflow received input: {}", input);
logger.info("Workflow input: {}", input);

// Call an activity in another app by passing in an active appID to the WorkflowTaskOptions
logger.info("Calling cross-app activity in 'app2'...");
logger.info("About to call cross-app activity in app2...");
String crossAppResult = ctx.callActivity(
logger.info("Calling multi-app activity in 'app2'...");
logger.info("About to call multi-app activity in app2...");
String multiAppResult = ctx.callActivity(
App2TransformActivity.class.getName(),
input,
new WorkflowTaskOptions("app2"),
String.class
).await();

// Call another activity in a different app
logger.info("Calling cross-app activity in 'app3'...");
logger.info("About to call cross-app activity in app3...");
logger.info("Calling multi-app activity in 'app3'...");
logger.info("About to call multi-app activity in app3...");
String finalResult = ctx.callActivity(
App3FinalizeActivity.class.getName(),
crossAppResult,
multiAppResult,
new WorkflowTaskOptions("app3"),
String.class
).await();
logger.info("Final cross-app activity result: {}", finalResult);
logger.info("Final multi-app activity result: {}", finalResult);

logger.info("CrossAppWorkflow finished with: {}", finalResult);
logger.info("MultiAppWorkflow finished with: {}", finalResult);
logger.info("=== WORKFLOW COMPLETING WITH: {} ===", finalResult);
ctx.complete(finalResult);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
limitations under the License.
*/

package io.dapr.examples.workflows.crossapp;
package io.dapr.examples.workflows.multiapp;

import io.dapr.workflows.client.DaprWorkflowClient;
import io.dapr.workflows.client.WorkflowInstanceStatus;
Expand All @@ -25,25 +25,25 @@
* 2. Start a new workflow instance
* 3. Wait for completion and get results
*/
public class CrossAppWorkflowClient {
public class MultiAppWorkflowClient {

public static void main(String[] args) {
if (args.length < 1) {
System.out.println("Usage: CrossAppWorkflowClientExample <input>");
System.out.println("Example: CrossAppWorkflowClientExample \"Hello World\"");
System.out.println("Usage: MultiAppWorkflowClientExample <input>");
System.out.println("Example: MultiAppWorkflowClientExample \"Hello World\"");
return;
}

String input = args[0];
System.out.println("=== Starting Cross-App Workflow Client ===");
System.out.println("=== Starting Multi-App Workflow Client ===");
System.out.println("Input: " + input);

try (DaprWorkflowClient client = new DaprWorkflowClient()) {
System.out.println("Created DaprWorkflowClient successfully");

// Start a new workflow instance
System.out.println("Attempting to start new workflow...");
String instanceId = client.scheduleNewWorkflow(CrossAppWorkflow.class, input);
String instanceId = client.scheduleNewWorkflow(MultiAppWorkflow.class, input);
System.out.printf("Started a new cross-app workflow with instance ID: %s%n", instanceId);

// Wait for the workflow to complete
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* limitations under the License.
*/

package io.dapr.it.testcontainers.workflows.crossapp;
package io.dapr.it.testcontainers.workflows.multiapp;

import io.dapr.workflows.WorkflowActivity;
import io.dapr.workflows.WorkflowActivityContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
* limitations under the License.
*/

package io.dapr.it.testcontainers.workflows.crossapp;
package io.dapr.it.testcontainers.workflows.multiapp;

import io.dapr.workflows.runtime.WorkflowRuntime;
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;

/**
* App2Worker - registers the App2TransformActivity.
* This app will handle cross-app activity calls from the main workflow.
* This app will handle multi-app activity calls from the main workflow.
*/
public class App2Worker {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* limitations under the License.
*/

package io.dapr.it.testcontainers.workflows.crossapp;
package io.dapr.it.testcontainers.workflows.multiapp;

import io.dapr.workflows.WorkflowActivity;
import io.dapr.workflows.WorkflowActivityContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
* limitations under the License.
*/

package io.dapr.it.testcontainers.workflows.crossapp;
package io.dapr.it.testcontainers.workflows.multiapp;

import io.dapr.workflows.runtime.WorkflowRuntime;
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;

/**
* App3Worker - registers the App3FinalizeActivity.
* This app will handle cross-app activity calls from the main workflow.
* This app will handle multi-app activity calls from the main workflow.
*/
public class App3Worker {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@
* limitations under the License.
*/

package io.dapr.it.testcontainers.workflows.crossapp;
package io.dapr.it.testcontainers.workflows.multiapp;

import io.dapr.workflows.runtime.WorkflowRuntime;
import io.dapr.workflows.runtime.WorkflowRuntimeBuilder;

/**
* CrossAppWorker - registers only the CrossAppWorkflow.
* MultiAppWorker - registers only the MultiAppWorkflow.
* This is the main workflow orchestrator that will call activities in other apps.
*/
public class CrossAppWorker {
public class MultiAppWorker {

public static void main(String[] args) throws Exception {
System.out.println("=== Starting CrossAppWorker (Workflow Orchestrator) ===");
System.out.println("=== Starting MultiAppWorker (Workflow Orchestrator) ===");

// Register the Workflow with the builder
WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder()
.registerWorkflow(CrossAppWorkflow.class);
.registerWorkflow(MultiAppWorkflow.class);

// Build and start the workflow runtime
try (WorkflowRuntime runtime = builder.build()) {
System.out.println("CrossAppWorker started - registered CrossAppWorkflow only");
System.out.println("MultiAppWorker started - registered MultiAppWorkflow only");
System.out.println("Waiting for workflow orchestration requests...");
runtime.start();
}
Expand Down
Loading
Loading