简体   繁体   中英

C# Retry two queries with Polly Retry

So I have 2 queries:

var a = await _aQuery.Execute(aId);
var b = await _bQuery.Execute(bId);

How can I retry execution of these queries with Polly Retry so that if any of them succeeds to get a non-null value, the code can proceed?

For example: 5 retries every 200ms and if query succeeds on a or on b , break the retries and proceed.

Let me alter your two operations a bit for the sake of simplicity.

static Random rnd = new();
static async Task<int?> OperationA()
{
    await Task.Delay(100); //Simulate I/O call's latency
    var number = rnd.Next();
    return number % 5 == 0 ? number : null;
}

static async Task<int?> OperationB()
{
    await Task.Delay(100);  //Simulate I/O call's latency
    var number = rnd.Next();
    return number % 4 == 0 ? number + 1 : null;
}
  • We have two operations ( OperationA and OperationB ) and they will either return null or an int
  • Their implementation are not important, they just serve demonstration purposes

Now If you need to define a retry policy which

  • Triggers if both operations failed
  • Triggers at most 5 times
  • Delays 200 milliseconds between each attempt

then you can do that like this:

var retryUntilGetResult = Policy<(int?, int?)>
    .HandleResult(((int? OpA, int? OpB) results) => !results.OpA.HasValue && !results.OpB.HasValue)
    .WaitAndRetryAsync(retryCount: 5, _ => TimeSpan.FromMilliseconds(200));
  • The Policy<(int?, int?)> part says that your return type is a tuple with two nullable integers
  • The HandleResult part says that if the returned tuple ( results ) does not contain any integer ( ....HasValue ) then the policy should trigger
  • The WaitAndRetryAsync part says you want to decorate an async method with this policy
  • The policy should fire at most 5 times, but wait 200 milliseconds between each attempt

The usage of this policy looks like this:

var result = await retryUntilGetResult.ExecuteAsync(async () =>
{
    Task<int?> opA = OperationA();
    Task<int?> opB = OperationB();
    await Task.WhenAll(opA, opB);
    return (await opA, await opB);
});
  • We fire of two Tasks and we are waiting for both to complete
  • Then we return a new tuple where we pass the results of the async operations

For the sake of completeness here the full source code:

static async Task Main()
{
    var retryUntilGetResult = Policy<(int?, int?)>
        .HandleResult(((int? OpA, int? OpB) results) => !results.OpA.HasValue && !results.OpB.HasValue)
        .WaitAndRetryAsync(retryCount: 5, _ => TimeSpan.FromMilliseconds(200));

    var result = await retryUntilGetResult.ExecuteAsync(async () =>
    {
        Task<int?> opA = OperationA();
        Task<int?> opB = OperationB();
        await Task.WhenAll(opA, opB);
        return (await opA, await opB);
    });
    Console.WriteLine(result);
}

static Random rnd = new();
static async Task<int?> OperationA()
{
    await Task.Delay(100); //Simulate I/O call's latency
    var number = rnd.Next();
    return number % 5 == 0 ? number : null;
}

static async Task<int?> OperationB()
{
    await Task.Delay(100);  //Simulate I/O call's latency
    var number = rnd.Next();
    return number % 4 == 0 ? number + 1 : null;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM