Using Polly to retry after HttpStatusCode.Unauthorized
I'm replying to this old question just to point out the Polly wiki page where this pattern was official documented:
retry-to-refresh-authorization
In particular this is the code snippet suggested:
var authorisationEnsuringPolicy = Policy
.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.Unauthorized)
.RetryAsync(
retryCount: 1, // Consider how many retries. If auth lapses and you have valid credentials, one should be enough; too many tries can cause some auth systems to blacklist.
onRetryAsync: async (outcome, retryNumber, context) => FooRefreshAuthorizationAsync(context),
/* more configuration */);
var response = authorisationEnsuringPolicy.ExecuteAsync(context => DoSomethingThatRequiresAuthorization(context), cancellationToken);
The
FooRefreshAuthorizationAsync(...)
method can obtain a new authorization token and pass it to the delegate executed through the policy usingPolly.Context
.
I might be late to the game but I leave here a post for future readers. I have created two slightly different solutions for this refresh token with retry problem.
Retry policy, Delegating Handler and Custom exception
- Here is sequence diagram which depicts the communication flow
- Here is the full source code
Retry policy, Delegating Handler and Polly.Context
This version separates the responsibilities in a different way:
- Here is sequence diagram which depicts the communication flow
- Here is the full source code
To use ExecuteAsync()
you must declare the policy as .RetryAsync(...)
, not .Retry(...)
.
If your actual code reads exactly as the code sample above, the .ExecuteAsync(...)
will be throwing for the mismatch between .Retry(...)
[a sync policy] and .ExecuteAsync(...)
[an async execution]. Since this exception is thrown, CallApiAsync()
is indeed never invoked. You should be able to see the thrown exception, when calling MakeGetRequestAsync()
Overall code approach looks good tho: this retry-refreshing-authentication is a proven pattern with Polly!