I have a sequence of numbers that are processed using an async method. I'm simulating a remote service call that may fail. In case of failure, I would like to retry until the call successes.
The problem is that with the code I'm trying, every time an exception is thrown in the async method, the sequence seems to hang forever.
You can test it with this simple code snippet (it's tested in LINQPad)
Random rnd = new Random();
void Main()
{
var numbers = Enumerable.Range(1, 10).ToObservable();
var processed = numbers.SelectMany(n => Process(n).ToObservable().Retry());
processed.Subscribe( f => Console.WriteLine(f));
}
public async Task<int> Process(int n)
{
if (rnd.Next(2) == 1)
{
throw new InvalidOperationException();
}
await Task.Delay(2000);
return n*10;
}
It should process every element, retrying the ones that have failed. Instead, it never ends and I don't know why.
How can I make it to do what I want?
EDIT: (thanks @CharlesNRice and @JonSkeet for the clues!):
This works!
Random rnd = new Random();
void Main()
{
var numbers = Enumerable.Range(1, 10).ToObservable();
var processed = numbers.SelectMany(n => RetryTask(() => MyTask(n)).ToObservable());
processed.Subscribe(f => Console.WriteLine(f));
}
private async Task<int> MyTask(int n)
{
if (rnd.Next(2) == 1)
{
throw new InvalidOperationException();
}
await System.Threading.Tasks.Task.Delay(2000);
return n * 10;
}
async Task<T> RetryTask<T>(Func<Task<T>> myTask, int? retryCount = null)
{
while (true)
{
try
{
return await myTask();
}
catch (Exception)
{
Debug.WriteLine("Retrying...");
if (retryCount.HasValue)
{
if (retryCount == 0)
{
throw;
}
retryCount--;
}
}
}
}