Whenever we are talking about resilience strategies then we mainly referring to a combination of resilient patterns. In other words in order to solve your problem you need to chain some polly polices (in the right order) to be able to tackle it. (In polly nomenclature it is called wrapping)
First let's collect the patterns:
Detecting that a Service is down
I would suggest to use the wording temporarily unavailable / unreachable because that means you want to use a resilient strategy to overcome of a transient failure. So in order to detect that a service is unavailable you can use the Circuit Breaker. It works in the following way:
This component acts as a proxy and examines the result (if any) of the requests. After a predefined number of successive / subsequent failures it will block the communication for a given time period against the downstream system. When that time period elapsed then it will allow you give it a try and see whether or not the new request is succeeding or failing.
It's worth mentioning here that Polly will throw a BrokenCircuitException
whenever the proxy is blocking the outgoing requests in order to satisfy the fail fast principle.
Caching the result
Whenever you are about to cache the result of an outbound request then you should consider the following concerns:
- Is that data is time sensitive? (So, using stale data is not an option)
- If it time sensitive then is there any timeframe when it can be still considered as valid response?
- Is that data is consumer specific? (So,using the same data across multiple consumer is not an option)
- etc.
By reviewing these questions you can decide whether or not to use caching.
Using Fallback
This simple pattern provides you the ability to use something as substitute. So in your case whenever the server is unavailable then fallback to the cache.
Now let's put them together.
The ordering is important here because Polly using escalation to chain policies. When the inner policy fails then it escalates that to the outer policy.
In your case the order would be like this (from outer to inner):
Fallback >> Cache >> Circuit Breaker
Of course, you can even enhance that by using Timeout and Retry as well. In that case the ordering would look like this:
Fallback >> Cache >> Retry >> Circuit Breaker >> Timeout
- Try to execute a call under a given time-frame
- Scrutinize your subsequent responses and prevent cascading failure in case of transient failure
- Retry the call n times and wait between retries
- If it succeeded then cache it
- If it failed then use the previously cached value
For further details about PolicyWrap please read their wiki page.