I have the following requirement that I can't really figure out how to solve.
Using Polly in C#/.NET: Given an user defined timeout and an internally/system defined retry strategy. How can I get the result from the latest retry attempt when the timeout is expired?
I have come up with this solution, but it seems odd that I have to capture the result like in the following code. If I do not have the timeout + fallback strategy ExecuteAsyc will return the latest attempt by itself.
var pipelineBuilder = new ResiliencePipelineBuilder<(Orders.Contracts.OrderView?, RequestResult)>();
(Orders.Contracts.OrderView?, RequestResult) outerTempResult = new(null, new()); // A non-empty temp result for fallbacks.
var pipeline = pipelineBuilder
.AddFallback(new()
{
ShouldHandle = new PredicateBuilder<(Orders.Contracts.OrderView?, RequestResult)>().Handle<TimeoutRejectedException>(),
FallbackAction = args => Outcome.FromResultAsValueTask(outerTempResult),
})
.AddTimeout(TimeSpan.FromMilliseconds(options.MaxPollingTimeout)) // Global timeout for the entire pipeline
.AddRetry(new RetryStrategyOptions<(Orders.Contracts.OrderView?, RequestResult)>
{
ShouldHandle = new PredicateBuilder<(Orders.Contracts.OrderView?, RequestResult)>()
.HandleResult(newOrder => newOrder.Item1 == null || newOrder.Item1.Status == S4.Orders.Contracts.OrderStatus.InProgress),
Delay = TimeSpan.FromMilliseconds(OrderSettings.RetryInterval),
MaxRetryAttempts = OrderSettings.RetryCount,
BackoffType = DelayBackoffType.Linear,
UseJitter = true,
OnRetry = (args) =>
{
outerTempResult = args.Outcome.Result; // Assign this to an outer variable to use in the fallback handling callback.
return ValueTask.CompletedTask;
}
})
.Build();
And the request execution looks like this:
var orderView = await pipeline.ExecuteAsync(async token =>
{
return await this.orderServiceClient.GetOrderAsync(id);
}, CancellationToken.None);
return orderView.Item2.ToApiResult();
There is probably something obvious I am missing here...