Search code examples
c#exceptionpollyresiliencytransient-failure

Polly fallback action did not throw the specified exception. What happened?


Given this code that tries to call AuthenticationManager.Authenticate() for 10 times, and then throws a CustomException after 10 failed attempts:

string res = Policy
    .Handle<Exception>() // Handles any exception
    .OrResult<string>(result => string.IsNullOrWhiteSpace(result)) // or if result is null
    .Fallback(() => throw new CustomException("Exception!")) // Not being thrown after 10 unsuccessful attempts
    .Wrap(
        Policy
            .Handle<Exception>()
            .OrResult<string>(result => string.IsNullOrWhiteSpace(result))
            .WaitAndRetry(
                10,
                retryAttempt => TimeSpan.FromSeconds(60),
                onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Authentication failed. Retrying after 60 seconds...(Attempt {retryCount} of 10)")))
    .ExecuteAndCapture(() => AuthenticationManager.Authenticate())
    .Result;

Why is the CustomException not being thrown from the fallback action? What should be the correct way to do it?


Solution

  • Found that just using WaitAndRetry and just checking for the Outcome worked for me (in case anyone comes across this question):

    var policyResult = Policy
        .Handle<Exception>()
        .OrResult<AuthenticationResult>(result => result is null)
            .WaitAndRetry(
                10,
                retryAttempt => TimeSpan.FromSeconds(60),
                onRetry: (response, delay, retryCount, context) => Trace.WriteLine($"[{DateTime.UtcNow}] Call failed. Retrying after 60 seconds...(Attempt {retryCount} of 10)"))
        .ExecuteAndCapture(() => AuthenticationManager.Authenticate());
    
    if (policyResult.Outcome == OutcomeType.Failure)
    {
        throw new CustomException("FAILED", policyResult.FinalException);
    }
    
    else
    {
        string value = policyResult.FinalHandledResult;
    }