Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question]: How to define a Policy per HttpMessage Method Type (GET, POST etc.) #2403

Open
sndpyadav34 opened this issue Nov 22, 2024 · 2 comments
Labels

Comments

@sndpyadav34
Copy link

What are you wanting to achieve?

I have a common HttpClient that is used or sending multiple requests like GET, POST, PUT etc. I am trying to configure different retry behavior for GET versus POST/PUT calls. Basically I am trying to configure a timeout per retry behavior for GET calls and a transient error behavior for POST/PUT calls.

What code or approach do you have so far?

I defined following two policies. policy1 handles the result of GET requests and handles the TimeoutRejectedException
along with transient errors whereas policy2 handles transient errors for requests other than GET. I then wrap both policies.

Random jitterer = new Random();
 
var policy1 = Polly.Policy
        .HandleResult<HttpResponseMessage>(req => req.RequestMessage.Method == HttpMethod.Get)
        .OrTransientHttpError()
        .Or<BrokenCircuitException>()
        .Or<TimeoutRejectedException>()
        .WaitAndRetryAsync(3,
        sleepDurationProvider: (retryAttempt, ctx) =>
        {
            return TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
                        + TimeSpan.FromMilliseconds(jitterer.Next(1000, 3000));
        },
        onRetry: (outcome, timespan, retryAttempt, context) =>
        {
            //LogRetry(services, outcome, timespan, retryAttempt, context);
        });
 
var policy2 = Polly.Policy
        .HandleResult<HttpResponseMessage>(req => req.RequestMessage.Method != HttpMethod.Get)
        .OrTransientHttpError()
        .Or<BrokenCircuitException>()
        .WaitAndRetryAsync(3,
        sleepDurationProvider: (retryAttempt, ctx) =>
        {
            return TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
                        + TimeSpan.FromMilliseconds(jitterer.Next(1000, 3000));
        },
        onRetry: (outcome, timespan, retryAttempt, context) =>
        {
            //LogRetry(services, outcome, timespan, retryAttempt, context);
        });
 
var combinedPolicy = Polly.Policy.WrapAsync(policy1, policy2);

And then while registering the HttpClient I add the retry policy handlers as below:

services.AddHttpClient<IPlatformHttpClient, PlatformHttpClient>()
    .AddPolicyHandler(combinedPolicy)
    .AddPolicyHandler(GetCircuitBreakerPolicy())
    .AddPolicyHandler(Polly.Policy.TimeoutAsync<HttpResponseMessage>(5));

However, with the policies configured like this, I see retries happening for both GET and POST requests. I think it's because of the timeout policy around the HttpClient. Not sure if it's possible to define on a single client like this.

Additional context

No response

@martincostello
Copy link
Member

Here's some code that uses different policies depending on the HTTP method.

Two different policies are added to a policy registry, one for "reads" and one for "writes": https://github.com/martincostello/alexa-london-travel-site/blob/5dc4c38445a6d7e1bb445898f5523b8b5f94eb0f/src/LondonTravel.Site/Extensions/PollyServiceCollectionExtensions.cs

The appropriate policy is then obtained from the registry based on the HTTP method of the current request: https://github.com/martincostello/alexa-london-travel-site/blob/0a6829fc01976f673cf9f26bcbf0dae36d72199a/src/LondonTravel.Site/Extensions/IHttpClientBuilderExtensions.cs#L90

@peter-csala
Copy link
Contributor

Side note

The AddPolicyHandler call registers a PolicyHttpMessageHandler which is a DelegatingHandler. I would suggest to combine all your policies into a single Policy.WrapAsync and register only a single DelegatingHandler instead of three.

.AddPolicyHandler(Policy.WrapAsync(retryForGet, retryForNonGet, circuitBreaker, perRequestTimeout));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants