@@ -53,6 +53,7 @@ Those examples contain the following workflow patterns:
53534 .  [ External Event Pattern] ( #external-event-pattern ) 
54545 .  [ Child-workflow Pattern] ( #child-workflow-pattern ) 
55556 .  [ Compensation Pattern] ( #compensation-pattern ) 
56+ 7 .  [ Cross-App Pattern] ( #cross-app-pattern ) 
5657
5758### Chaining Pattern  
5859In the chaining pattern, a sequence of activities executes in a specific order.
@@ -681,6 +682,158 @@ Key Points:
6816824 .  Each activity simulates work with a short delay for demonstration purposes
682683
683684
685+ ### Cross-App Pattern  
686+ 
687+ 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.
688+ 
689+ The ` CrossAppWorkflow `  class defines the workflow. It demonstrates calling activities in different apps using the ` appId `  parameter in ` WorkflowTaskOptions ` . See the code snippet below:
690+ ``` java 
691+ public  class  CrossAppWorkflow  implements  Workflow  {
692+   @Override 
693+   public  WorkflowStub  create () {
694+       return  ctx - >  {
695+           var  logger =  ctx. getLogger();
696+           logger. info(" === WORKFLOW STARTING ===" 
697+           logger. info(" Starting CrossAppWorkflow: {}" . getName());
698+           logger. info(" Workflow name: {}" . getName());
699+           logger. info(" Workflow instance ID: {}" . getInstanceId());
700+ 
701+           String  input =  ctx. getInput(String . class);
702+           logger. info(" CrossAppWorkflow received input: {}" 
703+           logger. info(" Workflow input: {}" 
704+ 
705+           //  Call an activity in another app by passing in an active appID to the WorkflowTaskOptions
706+           logger. info(" Calling cross-app activity in 'app2'..." 
707+           logger. info(" About to call cross-app activity in app2..." 
708+           String  crossAppResult =  ctx. callActivity(
709+                   App2TransformActivity . class. getName(),
710+                   input,
711+                   new  WorkflowTaskOptions (" app2" 
712+                   String . class
713+           ). await();
714+ 
715+           //  Call another activity in a different app
716+           logger. info(" Calling cross-app activity in 'app3'..." 
717+           logger. info(" About to call cross-app activity in app3..." 
718+           String  finalResult =  ctx. callActivity(
719+                   App3FinalizeActivity . class. getName(),
720+                   crossAppResult,
721+                   new  WorkflowTaskOptions (" app3" 
722+                   String . class
723+           ). await();
724+           logger. info(" Final cross-app activity result: {}" 
725+           logger. info(" Final cross-app activity result: {}" 
726+ 
727+           logger. info(" CrossAppWorkflow finished with: {}" 
728+           logger. info(" === WORKFLOW COMPLETING WITH: {} ===" 
729+           ctx. complete(finalResult);
730+       };
731+   }
732+ }
733+ 
734+ ``` 
735+ 
736+ The ` App2TransformActivity `  class defines an activity in app2 that transforms the input string. See the code snippet below:
737+ ``` java 
738+ public  class  App2TransformActivity  implements  WorkflowActivity  {
739+   @Override 
740+   public  Object  run (WorkflowActivityContext  ctx ) {
741+     var  logger =  ctx. getLogger();
742+     logger. info(" === App2: TransformActivity called ===" 
743+     String  input =  ctx. getInput(String . class);
744+     logger. info(" Input: {}" 
745+     
746+     //  Transform the input
747+     String  result =  input. toUpperCase() +  "  [TRANSFORMED BY APP2]" 
748+ 
749+     logger. info(" Output: {}" 
750+     return  result;
751+   }
752+ }
753+ ``` 
754+ 
755+ The ` App3FinalizeActivity `  class defines an activity in app3 that finalizes the processing. See the code snippet below:
756+ ``` java 
757+ public  class  App3FinalizeActivity  implements  WorkflowActivity  {
758+   @Override 
759+   public  Object  run (WorkflowActivityContext  ctx ) {
760+     var  logger =  ctx. getLogger();
761+     logger. info(" === App3: FinalizeActivity called ===" 
762+     String  input =  ctx. getInput(String . class);
763+     logger. info(" Input: " 
764+     
765+     //  Finalize the processing
766+     String  result =  input +  "  [FINALIZED BY APP3]" 
767+ 
768+     logger. info(" Output: {}" 
769+     return  result;
770+   }
771+ }
772+ ``` 
773+ 
774+ ** Key Features:** 
775+ -  ** Cross-app activity calls** : Call activities in different Dapr applications specifying the appID in the WorkflowTaskOptions
776+ -  ** WorkflowTaskOptions with appId** : Specify which app should handle the activity
777+ -  ** Combined with retry policies** : Use app ID along with retry policies and handlers
778+ -  ** Error handling** : Works the same as local activity calls
779+ 
780+ ** Requirements:** 
781+ -  Multiple Dapr applications running with different app IDs
782+ -  Activities registered in the target applications
783+ -  Proper Dapr workflow runtime configuration
784+ 
785+ ** Important Limitations:** 
786+ -  ** Cross-app calls are currently supported for activities only** 
787+ -  ** Child workflow cross-app calls (suborchestration) are NOT supported** 
788+ -  The app ID must match the Dapr application ID of the target service
789+ 
790+ ** Running the Cross-App Example:** 
791+ 
792+ This example requires running multiple Dapr applications simultaneously. You'll need to run the following commands in separate terminals:
793+ 
794+ 1 .  ** Start the main workflow worker (crossapp-worker):** 
795+ ``` sh 
796+ 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
797+ ``` 
798+ 
799+ 2 .  ** Start app2 worker (handles App2TransformActivity):** 
800+ ``` sh 
801+ 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
802+ ``` 
803+ 
804+ 3 .  ** Start app3 worker (handles App3FinalizeActivity):** 
805+ ``` sh 
806+ 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
807+ ``` 
808+ 
809+ 4 .  ** Run the workflow client:** 
810+ ``` sh 
811+ 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" 
812+ ``` 
813+ 
814+ ** Expected Output:** 
815+ 
816+ The client will show:
817+ ``` text 
818+ === Starting Cross-App Workflow Client === 
819+ Input: Hello World 
820+ Created DaprWorkflowClient successfully 
821+ Attempting to start new workflow... 
822+ Started a new cross-app workflow with instance ID: 001113f3-b9d9-438c-932a-a9a9b70b9460 
823+ Waiting for workflow completion... 
824+ Workflow instance with ID: 001113f3-b9d9-438c-932a-a9a9b70b9460 completed with result: HELLO WORLD [TRANSFORMED BY APP2] [FINALIZED BY APP3] 
825+ ``` 
826+ 
827+ The workflow demonstrates:
828+ 1 .  The workflow starts in the main worker (crossapp-worker)
829+ 2 .  Calls an activity in 'app2' using cross-app functionality
830+ 3 .  Calls an activity in 'app3' using cross-app functionality
831+ 4 .  The workflow completes with the final result from all activities
832+ 
833+ This pattern is particularly useful for:
834+ -  Microservices architectures where activities are distributed across multiple services
835+ -  Multi-tenant applications where activities are isolated by app ID
836+ 
684837### Suspend/Resume Pattern  
685838
686839Workflow instances can be suspended and resumed. This example shows how to use the suspend and resume commands.
0 commit comments