diff --git a/release_notes.md b/release_notes.md index 28441f566..a8ec2ba33 100644 --- a/release_notes.md +++ b/release_notes.md @@ -10,6 +10,7 @@ - Fix issue with isolated entities: custom deserialization was not working because IServices was not passed along (https://github.com/Azure/azure-functions-durable-extension/pull/2686) - Fix issue with `string` activity input having extra quotes (https://github.com/Azure/azure-functions-durable-extension/pull/2708) +- Fix issue with out-of-proc entity operation errors: success/failure details of individual operations in a batch was not processed correctly (https://github.com/Azure/azure-functions-durable-extension/pull/2752) ### Breaking Changes diff --git a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs index cf45c2521..3383912c6 100644 --- a/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs +++ b/src/WebJobs.Extensions.DurableTask/OutOfProcMiddleware.cs @@ -374,15 +374,27 @@ void SetErrorResult(FailureDetails failureDetails) functionName.Name, batchRequest.InstanceId, functionResult.Exception.ToString(), - FunctionType.Orchestrator, + FunctionType.Entity, isReplay: false); - SetErrorResult(new FailureDetails( - errorType: "FunctionInvocationFailed", - errorMessage: $"Invocation of function '{functionName}' failed with an exception.", - stackTrace: null, - innerFailure: new FailureDetails(functionResult.Exception), - isNonRetriable: true)); + if (context.Result != null) + { + // Send the results of the entity batch execution back to the DTFx dispatch pipeline. + // This is important so we can propagate the individual failure details of each failed operation back to the + // calling orchestrator. Also, even though the function execution was reported as a failure, + // it may not be a "total failure", i.e. some of the operations in the batch may have succeeded and updated + // the entity state. + dispatchContext.SetProperty(context.Result); + } + else + { + SetErrorResult(new FailureDetails( + errorType: "FunctionInvocationFailed", + errorMessage: $"Invocation of function '{functionName}' failed with an exception.", + stackTrace: null, + innerFailure: new FailureDetails(functionResult.Exception), + isNonRetriable: true)); + } return; } @@ -399,8 +411,7 @@ void SetErrorResult(FailureDetails failureDetails) FunctionType.Entity, isReplay: false); - // Send the result of the orchestrator function to the DTFx dispatch pipeline. - // This allows us to bypass the default, in-process execution and process the given results immediately. + // Send the results of the entity batch execution back to the DTFx dispatch pipeline. dispatchContext.SetProperty(batchResult); }