I have a predefined IAsyncPolicy<HttpResponseMessage>
policy coming from an external assembly.
I want to apply this policy to a Http Client, BUT I want to exclude one of the cases this policy typically handles.
Take the example below:
- I cannot influence how the baseline policy is created (external library)
- I need to wire things up so that this policy is NOT invoked if the http client returns StatusCode.Forbidden
How can I do this?
void Configure(IHttpClientBuilder builder)
{
var policy = GetBaselinePolicy();
// TODO: Do something here to *not* have policy handle HttpStatusCode.Forbidden.. only what?
builder.AddPolicyHandler(policy);
}
// Assume you CANNOT change this function here
IAsyncPolicy<HttpResponseMessage> GetBaselinePolicy() {
return Policy<HttpResponseMessage>
.HandleResult(x => x.StatusCode is HttpStatusCode.Forbidden or HttpStatusCode.Gone)
.WaitAndRetryForeverAsync(_ => TimeSpan.FromSeconds(1));
}
I've found Policy.WrapAsync
, but best from what I've seen so far, this unconitionally chains policies, i.e. one way or the other the call would find its way to the baseline policy and be retried there forever.
I have a predefined IAsyncPolicy<HttpResponseMessage>
policy coming from an external assembly.
I want to apply this policy to a Http Client, BUT I want to exclude one of the cases this policy typically handles.
Take the example below:
- I cannot influence how the baseline policy is created (external library)
- I need to wire things up so that this policy is NOT invoked if the http client returns StatusCode.Forbidden
How can I do this?
void Configure(IHttpClientBuilder builder)
{
var policy = GetBaselinePolicy();
// TODO: Do something here to *not* have policy handle HttpStatusCode.Forbidden.. only what?
builder.AddPolicyHandler(policy);
}
// Assume you CANNOT change this function here
IAsyncPolicy<HttpResponseMessage> GetBaselinePolicy() {
return Policy<HttpResponseMessage>
.HandleResult(x => x.StatusCode is HttpStatusCode.Forbidden or HttpStatusCode.Gone)
.WaitAndRetryForeverAsync(_ => TimeSpan.FromSeconds(1));
}
I've found Policy.WrapAsync
, but best from what I've seen so far, this unconitionally chains policies, i.e. one way or the other the call would find its way to the baseline policy and be retried there forever.
- Did my proposed solution work for you? – Peter Csala Commented 2 days ago
1 Answer
Reset to default 0You can basically early exit with a fallback policy
IAsyncPolicy<HttpResponseMessage> GetEarlyExitPolicy()
=> Policy<HttpResponseMessage>
.HandleResult(x => x.StatusCode is HttpStatusCode.Forbidden)
.FallbackAsync(_ => Task.FromResult(new HttpResponseMessage((HttpStatusCode)0));
So, whenever you receive a Forbidden then you change the original result with a bogus one. The status code is intentionally out of the normal range to ease the detection.
Here is a working example:
public class Program
{
public static async Task Main()
{
var x = Policy.WrapAsync(GetBaselinePolicy(), GetEarlyExitPolicy());
var res = await x.ExecuteAsync(() => Task.FromResult(new HttpResponseMessage(HttpStatusCode.Forbidden)));
res.Dump();
}
static IAsyncPolicy<HttpResponseMessage> GetBaselinePolicy() {
return Policy<HttpResponseMessage>
.HandleResult(x => x.StatusCode is HttpStatusCode.Forbidden or HttpStatusCode.Gone)
.WaitAndRetryForeverAsync(_ => { "retry".Dump(); return TimeSpan.FromSeconds(1);});
}
static IAsyncPolicy<HttpResponseMessage> GetEarlyExitPolicy() {
return Policy<HttpResponseMessage>
.HandleResult(x => x.StatusCode is HttpStatusCode.Forbidden)
.FallbackAsync(_ => { "fallback".Dump(); return Task.FromResult(new HttpResponseMessage((HttpStatusCode)0)); });
}
}