|
| 1 | +# Multi App workflow Example |
| 2 | + |
| 3 | +This example demonstrates how you can create distributed workflows where the orchestrator doesn't host the workflow activities. |
| 4 | + |
| 5 | +For more documentation about how Multi App Workflows work [check the official documentation here](https://v1-16.docs.dapr.io/developing-applications/building-blocks/workflow/workflow-multi-app/). |
| 6 | + |
| 7 | +This example is composed by three Spring Boot applications: |
| 8 | +- `orchestrator`: The `orchestrator` app contains the Dapr Workflow definition and expose REST endpoints to create and raise events against workflow instances. |
| 9 | +- `worker-one`: The `worker-one` app contains the `RegisterCustomerActivity` definition, which will be called by the `orchestrator` app. |
| 10 | +- `worker-two`: The `worker-two` app contains the `CustomerFollowupActivity` definition, which will be called by the `orchestrator` app. |
| 11 | + |
| 12 | +To start the applications you need to run the following commands on separate terminals, starting from the `multi-app` directory. |
| 13 | +To start the `orchestrator` app run: |
| 14 | +```bash |
| 15 | +cd orchestrator/ |
| 16 | +mvn -Dspring-boot.run.arguments="--reuse=true" clean spring-boot:test-run |
| 17 | +``` |
| 18 | + |
| 19 | +The `orchestrator` application will run on port `8080`. |
| 20 | + |
| 21 | +On a separate terminal, to start the `worker-one` app run: |
| 22 | +```bash |
| 23 | +cd worker-one/ |
| 24 | +mvn -Dspring-boot.run.arguments="--reuse=true" clean spring-boot:test-run |
| 25 | +``` |
| 26 | + |
| 27 | +The `worker-one` application will run on port `8081`. |
| 28 | + |
| 29 | +On a separate terminal, to start the `worker-two` app run: |
| 30 | +```bash |
| 31 | +cd worker-two/ |
| 32 | +mvn -Dspring-boot.run.arguments="--reuse=true" clean spring-boot:test-run |
| 33 | +``` |
| 34 | + |
| 35 | +The `worker-two` application will run on port `8082`. |
| 36 | + |
| 37 | +You can create new workflow instances of the `CustomerWorkflow` by calling the `/customers` endpoint of the `orchestrator` application. |
| 38 | + |
| 39 | +```bash |
| 40 | +curl -X POST localhost:8080/customers -H 'Content-Type: application/json' -d '{ "customerName": "salaboy" }' |
| 41 | +``` |
| 42 | + |
| 43 | +The workflow definition [`CustomerWorkflow`](orchstrator/src/main/java/io/dapr/springboot/examples/orchestrator/CustomerWorkflow.java) that you can find inside the `orchestrator` app, |
| 44 | +performs the following orchestration when a new workflow instance is created: |
| 45 | + |
| 46 | +- Call the `RegisterCustomerActivity` activity which can be found inside the `worker-one` application. |
| 47 | + - You can find in the workflow definition the configuration to make reference to an Activity that is hosted by a different Dapr application. |
| 48 | + ```java |
| 49 | + customer = ctx.callActivity("io.dapr.springboot.examples.workerone.RegisterCustomerActivity", |
| 50 | + customer, |
| 51 | + new WorkflowTaskOptions("worker-one"), |
| 52 | + Customer.class). |
| 53 | + await(); |
| 54 | + ``` |
| 55 | +- Wait for an external event of type `CustomerReachOut` with a timeout of 5 minutes: |
| 56 | + ```java |
| 57 | + ctx.waitForExternalEvent("CustomerReachOut", Duration.ofMinutes(5), Customer.class).await(); |
| 58 | + ``` |
| 59 | +- You can check the status of the workflow for a given customer by sending the following request: |
| 60 | + ```shell |
| 61 | + curl -X POST localhost:8080/customers/status -H 'Content-Type: application/json' -d '{ "customerName": "salaboy" }' |
| 62 | + ``` |
| 63 | +- You can call the following endpoint on the `orchestrator` app to raise the external event: |
| 64 | + ```shell |
| 65 | + curl -X POST localhost:8080/customers/followup -H 'Content-Type: application/json' -d '{ "customerName": "salaboy" }' |
| 66 | + ``` |
| 67 | +- When the event is received, the workflow move forward to the last activity called `CustomerFollowUpActivity`, that can be found on the `worker-two` app. |
| 68 | + ```java |
| 69 | + customer = ctx.callActivity("io.dapr.springboot.examples.workertwo.CustomerFollowupActivity", |
| 70 | + customer, |
| 71 | + new WorkflowTaskOptions("worker-two"), |
| 72 | + Customer.class). |
| 73 | + await(); |
| 74 | + ``` |
| 75 | +- The workflow completes by handing out the final version of the `Customer` object that has been modified the workflow activities. You can retrieve the `Customer` payload |
| 76 | + by running the following command: |
| 77 | + ```shell |
| 78 | + curl -X POST localhost:8080/customers/output -H 'Content-Type: application/json' -d '{ "customerName": "salaboy" }' |
| 79 | + ``` |
| 80 | + |
| 81 | +## Testing Multi App Workflows |
| 82 | + |
| 83 | +Testing becomes a complex task when you are dealing with multiple Spring Boot applications. For testing this workflow, |
| 84 | +we rely on [Testcontainers](https://testcontainers.com) to create the entire setup which enable us to run the workflow end to end. |
| 85 | + |
| 86 | +You can find the end-to-end test in the [`OrchestratorAppIT.java`](orchestrator/src/test/java/io/dapr/springboot/examples/orchestrator/OrchestratorAppIT.java) class inside the `orchestrator` application. |
| 87 | +This test interact with the application REST endpoints to validate their correct execution. |
| 88 | + |
| 89 | +But the magic behind the test can be located in the [`DaprTestContainersConfig.class`](orchestrator/src/test/java/io/dapr/springboot/examples/orchestrator/DaprTestContainersConfig.java) which defines the configuration for |
| 90 | +all the Dapr containers and the `worker-one` and `worker-two` applications. Check this class to gain a deeper understand how to configure |
| 91 | +multiple Dapr-enabled applications. |
0 commit comments