Long Quanzheng
Long Quanzheng

Reputation: 2401

How to return the processing result of a signal?

Especially if the signal processing needs to invoke an/some activities, how can I achieve that?

I tried to return data or exception but it doesn't work.

Data cannot be returned from signal method. Throwing exception will block workflow execution.

Upvotes: 0

Views: 1112

Answers (1)

Long Quanzheng
Long Quanzheng

Reputation: 2401

Common mistakes

It's wrong to return data in a signal method, or throw an exception -- because signal method is meant to be Asynchronous. The processing must be like Kafka processing messages and you can't return the result via the method returning.

So below code will NOT work:

public class SampleWorkflow{
   public Result mySignalMethod(SignalRequest req){
      Result result = activityStub.execute(req)
      if(...){
          throw new RuntimeException(...)
      }
   return result
   }

}

What should you do

What you must do:

  • Make sure signal don't return anything
  • Use a query method to return the results
  • In signal method processing, store the results into workflow state so that query can return the states

A bonus if you also use the design pattern to store signal request into a queue, and let workflow method to process the signal. This will give you some benefits

  • Guarantee FIFO ordering of signal processing
  • Make sure reset workflow won't run into issues -- after reset, signals will be preserved and moved to earlier position of the workflow history. Sometimes workflow are not initialized to replay the signals.
  • Also make exception handling easier

See this design pattern in sample code: Cadence Java sample/Temporal java sample

If we applied all above, the sample code should be like below :

public class SampleWorkflow{

   private Queue<SignalRequest> queue = new Queue<>();
   private Response<Result> lastSignalResponse;

   public void myWorkflowMethod(){
        Async.procedure(
                () -> {
                    while (true) {
                        Workflow.await(() -> !queue.isEmpty());
                        final SignalRequest req =
                                queue.poll();
                        // alternatively, you can use async to start an activity:  
                        try{
                             Result result = activityStub.execute(req); 
                        }catch (ActivityException e){
                             lastSignalResponse = new Response( e );
                        }

                        if(...){
                            lastSignalResponse = new Response( new RuntimeException(...) );
                        }else{
                             lastSignalResponse = new Response( result);  
                        }
                    }
                });

      ...
   }

   public Response myQueryMethod(){
       return lastSignalResponse;
   }

   public Result mySignalMethod(SignalRequest req){
      queue.add(req)
   }

}

And in the application code, you should signal and then query the workflow to get the result:


  workflowStub.mySignalMethod(req)
  Response response = workflowStub.myQueryMethod()

Follow this sample-Cadence / sample-Temporal if you want to use aysnc activity

Why

Upvotes: 2

Related Questions