Workflow retry options ignore "setDoNotRetry"

Hi Team!

I am trying to create exception handling for my application that use retry rules both for workflows and activities.

I noticed that doNotRetry works fine for activities but not for workflows.
Below you can find complete code that reproduces my problem.

When I add MyException into doNotRetry when building workflow stub then whole workflow is being retried 3 times while I expect no retries at all (as an exception thrown from activity is also on workflow setDoNotRetry level).

Is there something I am doing wrong?

public class ExampleDoNotRetry {

  public static class MyException extends RuntimeException {

      public MyException(String message) {
          super(message);
      }
  }

  @ActivityInterface
  public interface MyActivity {

      @ActivityMethod
      void simpleThrow();
  }

  public static class MyActivityImpl implements MyActivity {

      @Override
      public void simpleThrow() {
          System.out.println("Activity should be executed only once!");
          throw new MyException("Hello! I am an exception");
      }
  }

  @WorkflowInterface
  public interface MyWorkflow {

      @WorkflowMethod
      void simpleWfThrow();
  }

  public static class MyWorkflowImpl implements MyWorkflow {

      @Override
      public void simpleWfThrow() {
          System.out.println("Workflow should be executed only once!");
          MyActivity myActivity = Workflow.newActivityStub(MyActivity.class, ActivityOptions.newBuilder()
                  .setTaskQueue("my")
                  .setStartToCloseTimeout(Duration.ofMinutes(1))
                  .setScheduleToStartTimeout(Duration.ofMinutes(1))
                  .setScheduleToCloseTimeout(Duration.ofMinutes(1))
                  .setRetryOptions(RetryOptions.newBuilder()
                          .setMaximumAttempts(3)
                          .setBackoffCoefficient(1.0)
                          .setDoNotRetry(MyException.class.getName())
                          .build())
                  .build());

          myActivity.simpleThrow();

          System.out.println("I should not reach this point!");
      }
  }

  public static void main(String[] args) {

      TestWorkflowEnvironment testWorkflowEnvironment = TestWorkflowEnvironment.newInstance(TestEnvironmentOptions.newBuilder()
              .setWorkflowClientOptions(WorkflowClientOptions.newBuilder()
                      .setNamespace("my")
                      .build()).build());

      Worker myWorker = testWorkflowEnvironment.newWorker("my");

      myWorker.registerWorkflowImplementationTypes(MyWorkflowImpl.class);
      myWorker.registerActivitiesImplementations(new MyActivityImpl());

      testWorkflowEnvironment.start();

      WorkflowClient workflowClient = testWorkflowEnvironment.getWorkflowClient();

      MyWorkflow myWorkflow = workflowClient.newWorkflowStub(MyWorkflow.class, WorkflowOptions.newBuilder()
              .setWorkflowId(UUID.randomUUID().toString())
              .setTaskQueue("my")
              .setWorkflowRunTimeout(Duration.ofMinutes(1))
              .setWorkflowTaskTimeout(Duration.ofSeconds(10))
              .setRetryOptions(RetryOptions.newBuilder()
                      .setMaximumAttempts(3)
                      .setBackoffCoefficient(1.0)
                      .setDoNotRetry(MyException.class.getName())
                      .build())
              .build());

      myWorkflow.simpleWfThrow();
  }
}

Workflows are not retried by default. I guess the workflow task is retried, which looks like the workflow is stuck. This is by design to support fixing bugs in production.

We don’t recommend failing workflows, so retrying them is rarely needed.

Thanks @maxim but in our application we need from time to time to retry workflows. What I am trying to do is to not retry a workflow in case of certain exception types. That is why I decided to use setDoNotRetry when building workflow stub - as below.

MyWorkflow myWorkflow = workflowClient.newWorkflowStub(MyWorkflow.class, WorkflowOptions.newBuilder()
              .setWorkflowId(UUID.randomUUID().toString())
              .setTaskQueue("my")
              .setWorkflowRunTimeout(Duration.ofMinutes(1))
              .setWorkflowTaskTimeout(Duration.ofSeconds(10))
              .setRetryOptions(RetryOptions.newBuilder()
                      .setMaximumAttempts(3)
                      .setBackoffCoefficient(1.0)
                      .setDoNotRetry(MyException.class.getName())
                      .build())
              .build());

Unfortunately it does not work as I was expecting and for exceptions defined in setDoNotRetry on the workflow level I still observe workflow retries instead of workflow failure.

You need to configure the workflow to fail on your exception first. Use WorkflowImplementationOptions.setFailWorkflowExceptionTypes for this:

WorkflowImplementationOptions workflowImplementationOptions =
        WorkflowImplementationOptions.newBuilder()
            .setFailWorkflowExceptionTypes(MyException.class)
            .build();
...

 worker.registerWorkflowImplementationTypes(
        workflowImplementationOptions, MyWorkflowImpl.class);

Another option is to throw non-retryable ApplicationFailure created through ApplicationFailiure.newNonRetryableFailure. ApplicationFailure doesn’t need to be configured with the WorkflowImplementationOptions.

Thanks @maxim that resolved the problem.