App-vNext / Polly

Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout, Bulkhead Isolation, and Fallback in a fluent and thread-safe manner. From version 6.0.1, Polly targets .NET Standard 1.1 and 2.0+.
https://www.thepollyproject.org
BSD 3-Clause "New" or "Revised" License
13.44k stars 1.23k forks source link

Can Polly's Caching Policy cache selectively based on response? (eg cache only 200ok http responses) #498

Closed citrus7 closed 1 year ago

citrus7 commented 6 years ago

Is Polly able to cache selectively based off of parameters like response code, response headers, etc



I could not find any documentation on what types of responses Polly decides to cache, or whether it's possible to cache selectively based on attributes like the response code. Right now a workaround I've tried is using ResultTtl to vary the ttl based on response code, and setting a very short ttl for non 200 responses.

Is there any good way to have the cache policy ignore all responses that are not 200?

reisenberger commented 6 years ago

@citrus7 Great question. ( /cc @stevejgordon, I think you also suggested/asked something similar once)

You can make Polly not cache a returned result by configuring CachePolicy with a ResultTtl (a strategy which determines the ttl to apply based on the result returned), such that it returns TimeSpan.Zero ttl for items you don't want to cache:

Func<Context, HttpResponseMessage, Ttl> cacheOnly200OKfilter =
    (context, result) => new Ttl(
        timeSpan: result.StatusCode == HttpStatusCode.OK ? TimeSpan.FromMinutes(5) : TimeSpan.Zero, 
        slidingExpiration: /* whether you want sliding expiration for the cached cases */
    );

IAsyncPolicy<HttpResponseMessage> cacheOnly200OKpolicy = 
    Policy.CacheAsync<HttpResponseMessage>(
        cacheProvider: /* whatever cache provider you are using */,
        ttlStrategy: new ResultTtl(cacheOnly200OKfilter),
        onCacheError: /* whatever cache error logging */
    ); // or whatever richer CacheAsync overload taking an ITtlStrategy ttlStrategy

When the ITtlStrategy returns TimeSpan.Zero as the ttl, the policy intentionally doesn't even attempt to put the item to the cache. In other words, this is certain (not just lucky due to timing) to prevent such items being cached.


EDITED: for syntax

reisenberger commented 6 years ago

For future ref: It would be easily also to handle selective caching natively within Polly: this example commit shows a pattern (only applied to the async implementation and a single new overload). However, we would need carefully to consider how many policy configuration overloads should be added: current policy configuration syntax promotes a proliferation of overloads.

For now, documented the above ResultTtl : ITtlStrategy approach, which works well.

lindstromhenrik commented 5 years ago

As ResultTtl<TResult> : ITtlStrategy<TResult> and ITtlStrategy<TResult> does not extend ITtlStrategy it may be worth to point out that the cache provider need to implement IAsyncCacheProvider<TResult>, i.e it is incompatible with for example the MemoryCacheProvider.

reisenberger commented 5 years ago

@lindstromhenrik You can convert MemoryCacheProvider to a version generic in TResult using

myMemoryCacheProvider.AsyncFor<TResult>
// or (for sync usage)
myMemoryCacheProvider.For<TResult>

as described in the MemoryCacheProvider documentation.

lindstromhenrik commented 5 years ago

Thanks, sorry I missed that.

reisenberger commented 4 years ago

Triage of issues: As previously mentioned, at present we do not want to add further policy configuration overloads, as the plan is to simplify these for Polly v8. However, this feature will be easy to implement - and is planned to be added - once the new syntax is in place.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open for 60 days with no activity. It will be automatically closed in 14 days if no further updates are made.

github-actions[bot] commented 1 year ago

This issue was closed because it has been inactive for 14 days since being marked as stale.