19

I'm trying to retry a failed operation 3 times.

I'm using Polly for a retry operation.

I want to get the exception in case the retry operation fails and retry again 2 times and so on.

return await Policy
           .Handle<CustomException>()
           .RetryAsync(3, onRetryAsync: async (exception, retryCount, context) =>
           {
               return await runner.run(params);
           });

The function should return

Task<IReadOnlyCollection<string>>

I'm getting the following error:

async lambda expression converted to a task returning delegate cannot return a value

d219
  • 2,707
  • 5
  • 31
  • 36
Ace
  • 831
  • 2
  • 8
  • 28

1 Answers1

34

I think it is unusual to run your logic in the retry policy - unless I misunderstand your question. More typically you execute the policy by calling a method that runs your logic.

Something like this:

async Task Main()
{
    var polly = Policy
           .Handle<Exception>()        
           .RetryAsync(3, (exception, retryCount, context) => Console.WriteLine($"try: {retryCount}, Exception: {exception.Message}"));

    var result = await polly.ExecuteAsync(async () => await DoSomething());
    Console.WriteLine(result);
}

int count = 0;

public async Task<string> DoSomething()
{
    if (count < 3)
    {
        count++;
        throw new Exception("boom");
    }

    return await Task.FromResult("foo");
}

output

try: 1, Exception: boom
try: 2, Exception: boom
try: 3, Exception: boom
foo
Crowcoder
  • 11,250
  • 3
  • 36
  • 45
  • I think you got my question pretty much. Just to make sure I got it. If the exception would be thrown, DoSomething would run again and if not it will return the result but will not run again? – Ace Dec 23 '19 at 14:36
  • 2
    Correct, `result` will contain whatever your method returns. If it failed too many times it would just act like it threw an exception normally. – Crowcoder Dec 23 '19 at 14:39
  • ok. 2 questions to validate: 1. So if there will be no exception, the same one which failed and no passed won't run again even if we didn't complete the number of retries? 2. Is there a way that polly can pass the exception to DoSomething? – Ace Dec 23 '19 at 15:54
  • correct typo for question 1 "So if there will be no exception, the same one which failed and NOW passes won't run again even if we didn't complete the number of retries – Ace Dec 23 '19 at 16:02
  • 1
    I'm not sure I understand question #1 - that form of Retry policy will try up to 3 times if it needs to. It will not retry at all if no exception that it handles is thrown. #2 - you don't need the exception passed to `DoSomething` because that is where the exception is coming from. You can just use normal `try/catch`. – Crowcoder Dec 23 '19 at 16:11
  • Thank you for question 1. about question 2: I do need the exception because I have data inside that I need to use for the next retry – Ace Dec 23 '19 at 16:29
  • 1
    In the retry delegate you can set or call something that sets a variable that is accessible by (in this example) `DoSomething`. You could write logic based on it. – Crowcoder Dec 23 '19 at 16:37
  • 1
    There are overloads of the Retry policy in which the `onRetry` delegate is passed `Polly.Context`. And there are overloads of `ExecuteAsync(...)` where the delegate executed can be passed `Polly.Context` as an input parameter. Thus, you can share data by storing it in the dictionary on `Polly.Context`. See https://github.com/App-vNext/Polly/wiki/Keys-And-Context-Data#using-context-for-custom-data ; http://www.thepollyproject.org/2017/05/04/putting-the-context-into-polly/ . Sharing data via `Polly.Context` avoids sharing a local variable; useful if policy defn is in a different scope from use. – mountain traveller Dec 23 '19 at 17:38