Azure-functions-durable-extension: FunctionFailedException.InnerException is always of type System.Exception

Created on 22 Jun 2018  路  7Comments  路  Source: Azure/azure-functions-durable-extension

Issue

When an activity function or a sub-orchestration throws an exception, it propogates up to the parent orchestrator function as a FunctionFailedException. It contains an InnerException value which has the same message as the original exception, but the type information is not preserved. Rather, it is always a System.Exception.

Expected

Ideally, the original exception is preserved.

Root cause

The problem is with the serialization settings between when the exception is observed by the activity function executor (type information is written) and the parent orchestrator (type information is ignored). The fix may require changes to the Durable Task Framework.

bug dtfx fix-ready

All 7 comments

Any update on this issue?
In my opinion this is vital for proper error handling for activity functions, especially when using CallActivityWithRetryAsync

@armadak Still trying to figure out the right way to fix this. It turns out the serialization of exceptions in .NET is quite tricky for a variety of different reasons.

"{\"ExceptionType\":\"Microsoft.Azure.WebJobs.FunctionFailedException\",\"InnerExceptionType\":\"DurableTask.Core.Exceptions.TaskFailedExceptionDeserializationException\"}"

TaskFailedExceptionDeserializationException
Instead of trying to serialize/deserialize the whole exception object,

Can you not just throw the exception where it contains

public class ActivityException : Exception{

public string ActivityName{get;private set;}

public string ExceptionTypeName{get;private set;}
public string ExceptionTypeMessage{get;private set;}

public string InnerExceptionTypeName{get;private set;}
public string InnerExceptionTypeMessage{get;private set;}
}

I need to have at least ActivityName or FunctionName where the exception being thrown

@andrew-vandenbrink Thanks for the suggestion - Yes, that's one option I'm considering. It would likely look a little different though since we also want to make it usable in other languages supported by the Azure Functions runtime.

@cgillum I tried simple solution. Adding TypeNameHandling to exception serializer settings.
Exception objects always inherit Exception class, they are serialized to base class even if they do not exist.
https://github.com/Azure/azure-functions-durable-extension/compare/dev...shibayan:exception-serializer-setting

try
{
    await context.CallActivityWithRetryAsync<string>("Function1_Hello", new RetryOptions(TimeSpan.FromSeconds(5), 1)
    {
        Handle = ex =>
        {
            // It's work
            return ex.InnerException is InvalidOperationException;
        }
    }, null);
}
catch (FunctionFailedException ex) when (ex.InnerException is InvalidOperationException)
{
    // It's Work
}

image

Thanks

@shibayan Interesting - I'm wondering how I could I could have overlooked this 馃槄. Thank you for sharing the example. We'll take a look and see if we can use this approach to help resolve this item.

Resolved with v1.8.0 release.

Was this page helpful?
0 / 5 - 0 ratings