microsoft / durabletask-java

Java SDK for Durable Functions and the Durable Task Framework
MIT License
14 stars 7 forks source link

Fix the exception type for using retriable task in `allOf` method #171

Closed kaibocai closed 1 year ago

kaibocai commented 1 year ago

Issue describing the changes in this PR

Resolve https://github.com/microsoft/durabletask-java/issues/169

This PR fixes the exception type for using RetriableTask in allOf method.

Description of the issue:

For RetriableTask in allOf method if the task failed for exception, CompositeTaskFailedException is not thrown out instead it's a TaskFailedException being thrown out. The reason is that the CompositeTaskFailedException that built in exceptionPath haven't get chance to be obtained at future.get(), ContextImplTask.this.processNextEvent() will first threw a TaskFailedException

For example:

 @FunctionName("Parallel")
    public List<String> parallelOrchestratorSad(
            @DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx,
            ExecutionContext context) {
        try {
            List<Task<String>> tasks = new ArrayList<>();
            RetryPolicy policy = new RetryPolicy(2, Duration.ofSeconds(15));
            TaskOptions options = new TaskOptions(policy);
            tasks.add(ctx.callActivity("AppendSad", "Input1", options, String.class));
            tasks.add(ctx.callActivity("AppendHappy", "Input2", options, String.class));
            return ctx.allOf(tasks).await();
        } catch (CompositeTaskFailedException e) {
            // Nothing will be caught for this type of exception. 
            for (Exception exception : e.getExceptions()) {
                if (exception instanceof TaskFailedException) {
                    TaskFailedException taskFailedException = (TaskFailedException) exception;
                    System.out.println("Task: " + taskFailedException.getTaskName() + " Failed for cause: " + taskFailedException.getErrorDetails().getErrorMessage());
                }
            }
        }
        return null;
    }

    @FunctionName("AppendHappy")
    public String appendHappy(
            @DurableActivityTrigger(name = "name") String name,
            final ExecutionContext context) {
        context.getLogger().info("AppendHappy: " + name);
        return name + "-test-happy";
    }

    @FunctionName("AppendSad")
    public String appendSad(
            @DurableActivityTrigger(name = "name") String name,
            final ExecutionContext context) {
        context.getLogger().info("Throw Test Exception: " + name);
        throw new NullPointerException("Test kaibocai exception");
    }

This PR ensures that any RetriableTask that is in allOf method is marked as isInCompoundTask so that later it uses this flag to decide whether to throw the exception or ignore it.

Pull request checklist

Additional information

Additional PR information

kaibocai commented 1 year ago

refer to https://github.com/microsoft/durabletask-java/pull/174