Simmy Chaos Engine for .NET – Part 7, Using a Random Chaos Policy

Full source code here.

This post builds on the previous one where I added chaos policies to a registry and dynamically configured their settings via a config file. In that example the chaos policy used was hard coded within the action method.

In this example the chaos policy will be chosen randomly from the available ones.

To accomplish this I have added an extension method to the Polly registry class. This method randomly chooses a chaos policy from the registry, you can find the source code from this in the attached file, it is not just a proof of concept and not designed to be robust.

Inside the controller the constructor remains the same as in the previous post.

public class BreweryController : Controller
{
	private readonly IHttpClientFactory _httpClientFactory;
	private readonly IPolicyRegistry<string> _policyRegistry;
	public BreweryController(IHttpClientFactory httpClientFactory, IPolicyRegistry<string> policyRegistry)
	{
		_policyRegistry = policyRegistry;
		_httpClientFactory = httpClientFactory;
	}

The action method then uses the registry extension method to choose a policy and make a request with the chaos policy.

var simmyPolicy = _policyRegistry.GetRandomChaosPolicy<AsyncMonkeyPolicy<HttpResponseMessage>>();
//snip..
var response =  await simmyPolicy.ExecuteAsync(async () => await httpClient.GetAsync(requestEndpoint));

If this is of use to you, you could consider adding another extension method to the registry to wrap multiple chaos policies together.

Full source code here.

Simmy Chaos Engine for .NET – Part 6, Configuring Policies Dynamically

Full source code here.

Simmy chaos policies have configurable options, via these options the polices can be turned on or off, have the rate at which they fire set, and in the case of the latency policy, the injected delay.

Here is an example of the fault policy –

AsyncInjectOutcomePolicy<HttpResponseMessage> faultPolicy = MonkeyPolicy.InjectFaultAsync<HttpResponseMessage>(
	new HttpRequestException("Simmy threw an exception, you should probably handle it in some way."),
	injectionRate: .5, //can be set through configuration
	enabled: () => true //can be set through configuration
);

And here is the latency policy –

var latencyPolicy = MonkeyPolicy.InjectLatencyAsync<HttpResponseMessage>(
	TimeSpan.FromSeconds(3), //can be set through configuration
	0.5, //can be set through configuration
	enabled: () => true); //can be set through configuration

This post shows how to set the all these settings via the appsettings.json file, but you could just as easily use a key store such as Consul or those provided by AWS and Azure. When you are using the application, change the values in appsettings.json and you will see the policies behave differently, try turning then on and off, changing the injection rate, and increasing/decreasing the delay.

In the appsettings.json I have something like –

{
  "SimmySettings": {
    "FaultPolicySettings": {
      "Enabled": false,
      "InjectionRate": 0.1
    },
    "LatencyPolicySettings": {
      "Enabled": true,
      "Latency": 3,
      "InjectionRate": 0.99
    }
  }
}

A matching FaultOptions.cs class.

namespace SimmyConfigurePolicies
{
    public class FaultOptions
    {
        public LatencyPolicySettings LatencyPolicySettings { get; set; }
        public FaultPolicySettings FaultPolicySettings { get; set; }
    }

    public class LatencyPolicySettings
    {
        public bool Enabled { get; set; }
        public double Latency { get; set; }
        public double InjectionRate { get; set; }

    }
    public class FaultPolicySettings
    {
        public bool Enabled { get; set; }
        public double InjectionRate { get; set; }
    }
}

The ConfigureServices method looks like this –

public void ConfigureServices(IServiceCollection services)
{
	services.AddOptions();

	services.Configure<FaultOptions>(Configuration.GetSection("SimmySettings"));
	services.AddPolicyRegistry();

	// Add the HttpClientFactory
	services.AddHttpClient("OpenBreweryDb", client =>
	{
		client.BaseAddress = new Uri("https://api.openbrewerydb.org/breweries/");
		client.DefaultRequestHeaders.Add("Accept", "application/json");
	});

	services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

Note the services.AddOptions, Microsoft recommends adding this, but I have found it works fine without.
Also notice that I have NOT added any policies to the registry, if you have been following along with this series of blog posts you might have noticed that I usually add the policies inside ConfigureServices.

Instead I have moved the policies to the Configure method because I need to get at the instance of FaultOptions that is inside the service collection. There are ways to do this from inside ConfigureServices, but Microsoft warns you not to do this.
But accessing the FaultOptions from inside Configure is just fine. I define the policies and use the value inside the FaultOptions to configure the two policies.

For the fault policy I added a methods to make accessing the FaultOptions easier (you can see these in the attached source code), and for the latency policy I access the values directly.

Then add the policies to the registry.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
	_faultOptions = app.ApplicationServices.GetService<IOptionsMonitor<FaultOptions>>();

	AsyncInjectOutcomePolicy<HttpResponseMessage> faultPolicy = MonkeyPolicy.InjectFaultAsync<HttpResponseMessage>(
		FaultToThrow, // 
		FaultPolicyInjectionRate,
		FaultPolicyEnabled
	 );

	AsyncInjectLatencyPolicy<HttpResponseMessage> latencyPolicy = MonkeyPolicy.InjectLatencyAsync<HttpResponseMessage>(
		 TimeSpan.FromSeconds(_faultOptions.CurrentValue.LatencyPolicySettings.Latency),
		 _faultOptions.CurrentValue.LatencyPolicySettings.InjectionRate,
		 () => _faultOptions.CurrentValue.LatencyPolicySettings.Enabled);

	var registry = app.ApplicationServices.GetRequiredService<IPolicyRegistry<string>>();
	registry.Add("FaultPolicy", faultPolicy);
	registry.Add("LatencyPolicy", latencyPolicy);
	if (env.IsDevelopment())
	{
		app.UseDeveloperExceptionPage();
	}

	app.UseMvc();
}

The policies are used in the BreweryController, in the constructor I add the HttpClientFactory and the policy registry.
In the action method grab the policy from the registry and use it to make the request to the remote service.

public class BreweryController : Controller
{
	private readonly IHttpClientFactory _httpClientFactory;
	private readonly IPolicyRegistry<string> _policyRegistry;
	public BreweryController(IHttpClientFactory httpClientFactory, IPolicyRegistry<string> policyRegistry)
	{
		_policyRegistry = policyRegistry;
		_httpClientFactory = httpClientFactory;
	}

	public async Task<IActionResult> Get(string state = "Massachusetts", string name = "night shift brewing")
	{
		var simmyPolicy = _policyRegistry.Get<AsyncMonkeyPolicy<HttpResponseMessage>>("LatencyPolicy");
		//var simmyPolicy = _policyRegistry.Get<AsyncMonkeyPolicy<HttpResponseMessage>>("FaultPolicy");
		string requestEndpoint = $"?by_state={state}&by_name={name}";

		var httpClient = _httpClientFactory.CreateClient("OpenBreweryDb");

		var response =  await simmyPolicy.ExecuteAsync( async () => await httpClient.GetAsync(requestEndpoint));
		if (response.IsSuccessStatusCode)
		{
			var breweries = await response.Content.ReadAsAsync<List<Brewery>>();
			return Ok(breweries);
		}

		return StatusCode((int)response.StatusCode, await response.Content.ReadAsStringAsync());
	}
}

There are a few improvements that can be made to this and I’ll show them over the next few posts, one is to select a random chaos policy from the registry and the second is to apply the chaos policies to HttpClientFactory policy selector.

Full source code here.

Simmy Chaos Engine for .NET – Part 5, Breaking Your Own Code

Full source code here.

The blog posts I have written so far about Simmy all deal with the scenario where you don’t have control over the source code that you want to break, in these cases Simmy policies are applied to the calling code.

In this post I’m going to show a very simple way of generating faults inside your own code. (For those of you familiar with Polly, you could use a policy registry, but I’m not going to in this example).

I have a Web Api application that has a very contrived RandomValueGenerator to return numbers and strings.

The RandomValueGenerator has fault policy that throws exceptions and a behavior policy that replaces good data with bad data.

The fault policy looks like this –

InjectOutcomePolicy _faultPolicy = MonkeyPolicy.InjectFault( 
    new Exception("Simmy threw an exception"),
    injectionRate: .5,
    enabled: () => true
);

50% of the time it will throw an exception.

The behavior policy looks like this –

InjectOutcomePolicy<NameAndLength> _corruptDataPolicy = MonkeyPolicy.InjectFault<NameAndLength>(
    new NameAndLength { Name = "xxxxx", Lenght = -100 },
    injectionRate: .5,
    enabled: () => true
);

50% of the time it will change the name to “xxxxx” and the length to -100.

Here’s how to use these policies inside the RandomValueGenerator

public string GetRandomName()
{
    return _faultPolicy.Execute(() => names[_random.Next(0, 5)]);
}

public int GetRandomNumber()
{
    return _faultPolicy.Execute(() => _random.Next(0, 100));
}

public NameAndLength GetNameAndLength()
{
    string name = names[_random.Next(0, 5)];
    NameAndLength nameAndLength = new NameAndLength { Name = name, Lenght = name.Length };
    return _corruptDataPolicy.Execute(() => nameAndLength);
}

As mentioned earlier, a policy registry might be a better way of passing and reusing the Simmy policies and this will be covered in the next post on Simmy.

Full source code here.

Simmy Chaos Engine for .NET – Part 4, Doing Some Real Damage, Dropping a Table

Full source code here.

Up until now the Simmy examples I’ve written have thrown exceptions, changed successes to failures or slowed down a request. None of these did any real damage to your system, and your application would probably have recovered when the next request came along.

But what about dropping a table? Poof, all the data is gone. Now what does your application do?

Doing this is very easy with the Behavior clause. Like the other clauses it takes a probability, an enabled flag, and action or func that executes any piece of code.

The Scenario
I have Web API application with a products controller that queries the database for a list of products.

During application start up the database is created and populated in Configure method of Startup.cs using the EnsureCreated() method and custom seed class.

Inside the controller the action method uses the SalesContext to query the database.

Inside the controller’s constructor I have the chaos policy, it is set to drop the Products table. The drop action of the behavior policy will execute 25% of the time the policy is run. If get an error when you run this saying that the table is absent, it means the chaos policy dropped the table, you’ll have to restart the application to run through the database seeding and creation again.

The policy looks like this –

public ProductsController(SalesContext salesContext)
{
	_behaviorPolicy = MonkeyPolicy.InjectBehaviourAsync(
		 async () =>
		 {
			 await _salesContext.Database.ExecuteSqlCommandAsync("DROP TABLE Products");
			 Console.WriteLine("Dropped the Products table.");
		 },
		 0.25, // 25% of the time this policy will execute
		async () => await Task.FromResult(true));
	_salesContext = salesContext;
}

The request to the _salesContext is made inside the policy, but the policy executes before the call the db is made and in 25% of such calls the table will be dropped.

[HttpGet]
public async Task<ActionResult> Get()
{
	List<Product> products =  await _behaviorPolicy.ExecuteAsync(async () => await _salesContext.Products.Take(10).ToListAsync());

	return Ok(products);
}

You can of course execute and code from inside the policy, wipe a cache, kill a service, delete a file, etc.

This example might be a little excessive in the damage it does, you can decide if it is unreasonable to expect you application to continue working even when the database is unavailable.

Full source code here.

Simmy Chaos Engine for .NET – Part 3, Adding Latency

Full source code here.

This is the third in my series on chaos engineering with Simmy. The first two posts dealt with the fault policy throwing exceptions and returning failed responses rather than calling the remote service.

In this I will show how to use the latency policy to inject delays into requests. It works in a similar way to the fault policy – a delay is chosen, the percentage of the time the delay should apply is chosen, and finally the policy is enabled/disabled.

When the policy is active, it delays the request, not the response.

var latencyPolicy = MonkeyPolicy.InjectLatencyAsync<HttpResponseMessage>(
    TimeSpan.FromSeconds(5), // inject a 5 second delay
    0.5, // in 50% of requests
    () => true); // policy is enabled

To see the effect of the latency policy I am going to add Polly timeout policy that throws an TimeoutRejectedException if no response is received from the OpenBreweryDb in 2 seconds.

I have also added a Polly retry policy to retry request that fail or timeout.

IAsyncPolicy<HttpResponseMessage> timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(2); 

The retry policy is set to retry up to three times.

IAsyncPolicy<HttpResponseMessage> retryPolicy = Policy
                .HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
                .Or<Exception>()
                .RetryAsync(3)

I have a policy wrap with the latency policy at the center, the timeout around it and finally the retry around that.

IAsyncPolicy<HttpResponseMessage> latencyTimeoutAndRetryPolicy = Policy.WrapAsync(
    retryPolicy, timeoutPolicy, latencyPolicy);

What happens is –
In 50% of the requests to the OpenBreweryDb, the latency policy delays the request by 5 seconds.
If the latency is active, the timeout policy throws a TimeoutRejectedException.
Then retry policy retries the request again.

If you run the application you will see the timeout and retry policies logging to the console.

That’s it, the latency policy is very easy to use.

Full source code here.

Simmy Chaos Engine for .NET – Part 2, Resilience and Injected Faults

Full source code here.

I wrote a blog on using a Simmy Fault policy a few days ago, it is very simple to use by itself, but it is far more useful when used in combination with a resilience policy.

Take the scenario where I have added retry logic to my requests, but the requests never fail, how do I know the retry logic works the way I expect. This is where the fault policy shines.

I’m going to build on the previous post where I injected a fault 50 percent of the time when making http requests. In the previous post I had Simmy throw a HttpRequestException but this time I’m going to have Simmy return a HttpResponseMessage containing an InternalServerError.

Along with the fault policy, I am going add a simple retry policy, retrying up to three times.

Here’s how it will work –

The fault policy executes –

If the fault policy is active and a fault is to be returned (remember this happens 50% of the time) a InternalServerError is returned. The HttpClient does NOT make a request to the remote service

The retry policy executes. The handles clause sees the InternalServerError and the behavior clause of the retry kicks in and performs the retry

The fault policy executes again

The preceding two steps repeat until a request succeeds or the retry policy reaches is limit of 3 retries

 

If the fault policy is not active, or a fault is NOT to be returned

the HTTP client executes the request to the remote service

the handles clause of the retry determines whether a retry should be performed

 

This is what it looks like –

At the center is the HttpReqeust, around it is the fault policy and around everything is the retry policy.

To achieve all this in code is very simple, in ConfigureServices add the fault policy.

public void ConfigureServices(IServiceCollection services)
{
	HttpResponseMessage faultHttpResponseMessage = new HttpResponseMessage(HttpStatusCode.InternalServerError)
	{
		Content = new StringContent("Simmy swapped the Ok for an Internal Server Error")
	};
	AsyncInjectOutcomePolicy<HttpResponseMessage> faultPolicy = MonkeyPolicy.InjectFaultAsync(
		faultHttpResponseMessage,
		injectionRate: .5,
		enabled: () => true 
	);

When the fault policy executes, 50% of the time it will return an InternalServerError response, preempting the real request to the remote service.

Next is the retry policy, its behavior clause triggers if the HttpResponseMessage is not a success.

IAsyncPolicy<HttpResponseMessage> retryPolicy = Policy
	.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
	.RetryAsync(3, onRetry: (message, retryCount) =>
	{
		Console.WriteLine($"Retry: {retryCount}");
	});

Wrap the retry policy around the fault policy.

AsyncPolicyWrap<HttpResponseMessage> faultAndRetryWrap = Policy.WrapAsync(retryPolicy, faultPolicy);

Finally, create the HttpClientFactory, passing in the policy wrap. If you are not familiar with how the HttpClientFactory works read Steve Gordon’s series or my blog posts on it. If you want know how it works with Polly, take a look at my posts on that topic.

services.AddHttpClient("OpenBreweryDb", client =>
{
	client.BaseAddress = new Uri("https://api.openbrewerydb.org/breweries/");
	client.DefaultRequestHeaders.Add("Accept", "application/json");
}).AddPolicyHandler(faultAndRetryWrap);

To fire of the HttpClient request inside the BreweryController remains the same –

string requestEndpoint = $"?by_state={state}&by_name={name}";
var httpClient = _httpClientFactory.CreateClient("OpenBreweryDb");
var response = await httpClient.GetAsync(requestEndpoint);

Full source code here.

Simmy Chaos Engine for .NET – Part 1, Injecting Faults

Full source code here.

For quite a while I have been writing, presenting and making videos about using Polly to make applications more stable.

With this post I’m starting a series on how break your applications with a chaos engine, the kind you might have heard about from the likes of NetFlix.

The team behind Polly released a chaos engineering module in June 2019. It allows you to inject faults, latency and arbitrary behavior into your application.

There are two general ways of using these policies –
1. Within your own business logic (if you have access to it).
2. Within the calls to business logic (if you can’t or don’t want to change it).

I’m going to deal with the latter case in this post. I want to see how my code responds when failures occur in third party dependencies, since I have no control over those dependencies I have to introduce the errors myself.

Making a good service go bad
In the provided code I have dependency on remote service and I want make it seem that that service suffers from a high percentage of faults.
This example will make GET requests to an API that looks up breweries, from what I can tell it is a highly reliable API, but I will make look as though 50% of requests to it fail. The point of doing this is to see how my application reacts to these errors – does it do so gracefully, or does it fall on its face.

If you made requests to the API without interfering with them you should see a 100% success rate. But I want to see failures, so I’ll use the Fault Policy to inject exceptions.

First, I added two NuGet packages to my project – Polly.Contrib.Simmy and Microsoft.Extensions.Http.Polly to the project.

In Startup.cs I add the fault policy.

AsyncInjectOutcomePolicy<HttpResponseMessage> faultPolicy = MonkeyPolicy.InjectFaultAsync<HttpResponseMessage>(
	new HttpRequestException("Simmy threw an exception"), 
		injectionRate: .5,
		enabled: () => true
	);

The parameters specify the exception to throw, the percentage of requests that throw the exception, and whether the policy is enabled. You can use set the injection rate and whether the policy is enabled via configuration, but I’m not going to show that here.
In this case, I am throwing an HttpRequestException 50% of the time, and the policy is enabled.

Then create a HttpClientFactory for the OpenBreweryDb

services.AddHttpClient("OpenBreweryDb", client =>
{
	client.BaseAddress = new Uri("https://api.openbrewerydb.org/breweries/");
	client.DefaultRequestHeaders.Add("Accept", "application/json");
}).AddPolicyHandler(faultPolicy);

If you are not yet using the HttpClientFactory, the source code has an example for you too, check the BreweryNoHttpClientFactoryController.

Start up the application, it should open on port 5000 and make a request to look up Night Shift Brewing in Massachusetts. There is a 50% chance of an exception occurring with each request.

Try it out. You’ll see that my application does not handle these failures very well, it simply returns the error to original caller.

That’s it, you are now starting down the road of mixing in some chaos into your application.

What then?
Great, my application fails, but we always knew it could. There’s not much point introducing failures unless you plan to handle them in some way, and this is where you might add a retry policy to improve you likelihood of a successful request.

Of course, the Polly retry, or wait and retry policies would be ideal. I’ll show how to do just that in the next post.

Full source code here.

Selectively Caching Values Inside HttpResponseMessage with Polly – caching series 3/3

Full source code here.

This is the last of three posts on caching with Polly. The first showed how to selectively cache HttpResponseMessages based on the status code of the response.

The second showed how to cache values inside the HttpResponseMessage rather than the whole of the response.

This final post will show how to selectively cache values inside the response based on the status of the response.

If you have read the previous posts the content of this will feel familiar.

Changes to Startup
Like the previous post, add a memory cache, a policy registry and a HttpClientFactory to the service collection.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    services.AddSingleton<IAsyncCacheProvider, MemoryCacheProvider>();

    IPolicyRegistry<string> registry = services.AddPolicyRegistry();

    services.AddHttpClient("RemoteServer", client =>
    {
        client.BaseAddress = new Uri("http://localhost:5000/api/");
        client.DefaultRequestHeaders.Add("Accept", "application/json");
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

What’s new is in the Configure method, fist step is to add the registry to the method parameters, DI will take care of this for us.

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
    IAsyncCacheProvider cacheProvider, IPolicyRegistry<string> registry)
{

Next is the cache filter, this one examines the tuple of int and HttpStatusCode and, if the HttpStatusCode is an OK the tuple will be cached for the duration specified. If the respones is not OK the filter will set the cache time to 0 which is interpreted as do not cache by the cache policy.

Func<Context, (int value, HttpStatusCode StatusCode), Ttl> cacheOnly200OkFilter =
	(context, result) => new Ttl(
		timeSpan: result.StatusCode == HttpStatusCode.OK ? TimeSpan.FromSeconds(5) : TimeSpan.Zero,
		slidingExpiration: true
	);

And this is the cache policy that uses the filter above to store the tuple.

IAsyncPolicy<(int, HttpStatusCode)> cachePolicy =
	Policy.CacheAsync<(int, HttpStatusCode)>(
		cacheProvider.AsyncFor<(int, HttpStatusCode)>(), 
		new ResultTtl<(int, HttpStatusCode)>(cacheOnly200OkFilter),
		onCacheError: null);

Lastly, add the policy to the registry.

registry.Add("cacheOnly200OkFilter", cachePolicy);

Changes to the Controller
Over in the CatalogController there many changes.

At the top I take in the HttpClientFactory and policy registry.

private readonly IHttpClientFactory _httpClientFactory;
private readonly IPolicyRegistry<string> _policyRegistry;

public CatalogController(IHttpClientFactory httpClientFactory, IPolicyRegistry<string> policyRegistry)
{
	_httpClientFactory = httpClientFactory;
	_policyRegistry = policyRegistry;
}

Inside the Get method, I setup grab the HttpClient from the HttpClientFactory, set the endpoint of the remote service, take the cache policy from the registry and setup the context for the cache policy to cache based on the incoming request. All of this is similar to normal usage of the Polly cache.

[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
    string requestEndpoint = $"inventory/{id}";
    var httpClient = _httpClientFactory.CreateClient("RemoteServer");

    var cachePolicy = _policyRegistry.Get<CachePolicy<(int, HttpStatusCode)>>("cacheOnly200Ok");
    Context policyExecutionContext = new Context($"GetInventoryById-{id}");	

As in the previous post I don’t call the HttpClient from inside the cache policy, instead I need to call something that returns the int and the HttpStatusCode. I use a local function that makes the request to the remote service, checks the response, deserializes the value and returns a tuple.

(int ItemsInStock, HttpStatusCode StatusCode) itemsInStockAndStatusCode =
    await cachePolicy.ExecuteAsync(context => MakeRequest(), policyExecutionContext);

// local function
async Task<(int count, HttpStatusCode statusCode)> MakeRequest()
{
    HttpResponseMessage response = await httpClient.GetAsync(requestEndpoint);

    if (response.IsSuccessStatusCode)
    {
        int itemsInStock = await response.Content.ReadAsAsync<int>();
        return (itemsInStock, response.StatusCode);
    }

    return (0, response.StatusCode);
}

When the cachePolicy is executed it first checks if there is value already in the cache, if there is, that will be returned and the local function will not be called. If there is no value in the cache, the local function is called, if the response of the local function is in the 200 range, the value is stored in the cache.

At this point, the action method has not returned anything to its caller.

Below the local function I check the tuple returned from the call to the cache policy and return a response.

if (itemsInStockAndStatusCode.StatusCode != HttpStatusCode.OK)
{
     return StatusCode((int)itemsInStockAndStatusCode.StatusCode);
}
return Ok(itemsInStockAndStatusCode.ItemsInStock);

For clarity, here is the full Get method.

[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
    string requestEndpoint = $"inventory/{id}";
    var httpClient = _httpClientFactory.CreateClient("RemoteServer");

    var cachePolicy = _policyRegistry.Get<CachePolicy<(int, HttpStatusCode)>>("cacheOnly200Ok");
    Context policyExecutionContext = new Context($"GetInventoryById-{id}");

    (int ItemsInStock, HttpStatusCode StatusCode) itemsInStockAndStatusCode =
        await cachePolicy.ExecuteAsync(context => MakeRequest(), policyExecutionContext);

    async Task<(int count, HttpStatusCode statusCode)> MakeRequest()
    {
        HttpResponseMessage response = await httpClient.GetAsync(requestEndpoint);

        if (response.IsSuccessStatusCode)
        {
            int itemsInStock = JsonConvert.DeserializeObject<int>(await response.Content.ReadAsSt
            return (itemsInStock, response.StatusCode);
        }

        // it doesn't matter what int you use here, it won't be cached as the StatusCode is not a
        return (0, response.StatusCode);
    }

    if (itemsInStockAndStatusCode.StatusCode != HttpStatusCode.OK)
    {
         return StatusCode((int)itemsInStockAndStatusCode.StatusCode);
    }
    return Ok(itemsInStockAndStatusCode.ItemsInStock);
}

Here endeth the series on caching.

Full source code here.

Caching Values Inside HttpResponseMessage with Polly – caching series 2/3

Full source code here.

In this, the second of three posts on caching in Polly, I will show how to cache the values returned inside a HttpResponseMessage as opposed to caching the response with all its various elements.

The first post explained how to selectively cache a response, based on the Http StatusCode. The third post will show how to combine these two ideas and selectively cache the values inside the HttpResponseMessage.

Caching the whole response or the value
Caching the whole HttpResponseMessage is useful if your business logic depends on interrogating the response for values outside the main payload or you want a quick and easy caching solution.

If on the other hand, you only need the payload, there is no need to cache the whole response.

Both cases are plausible, and it is up to do decide which is more appropriate for your application.

How to cache the value inside HttpResponseMessage
The first step is to set the cache inside ConfigureServices.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    services.AddSingleton<IAsyncCacheProvider, MemoryCacheProvider>();

Then in Configure, setup the policy to store the type you expect to find in the response. In this example it is in a int, but it could easily be a complex layered model representing anything.

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
    IAsyncCacheProvider cacheProvider, IPolicyRegistry<string> registry)
{
    CachePolicy<int> cachePolicy =
        Policy.CacheAsync<int>(cacheProvider, TimeSpan.FromSeconds(10));

    registry.Add("CachingPolicy", cachePolicy);

Note, how I specified an int rather than a HttpResponseMessage.

In the previous post, I used the HttpClientFactory to select the policy from a Polly policy registry. I could do that because the type I was storing was HttpResponseMessage, that is not the case now and HttpClientFactory will not play nice when trying to cache anything other than a HttpResponseMessage. Instead I’m going to pass the policy registry directly to the controller and get the policy from this, I am still using the HttpClientFactory to pass HttpClient, but not for policy selection.

Here is how the controller starts.

public class CatalogController : Controller
{
    private readonly IHttpClientFactory _httpClientFactory;
    private readonly IPolicyRegistry<string> _policyRegistry;

    public CatalogController(IHttpClientFactory httpClientFactory, IPolicyRegistry<string> policyRegistry)
    {
        _httpClientFactory = httpClientFactory;
        _policyRegistry = policyRegistry;
    }

And here is the GET method.

[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
    string requestEndpoint = $"inventory/{id}";
    var httpClient = _httpClientFactory.CreateClient("RemoteServer");

    var cachePolicy = _policyRegistry.Get<CachePolicy<int>>("CachingPolicy");
    Context policyExecutionContext = new Context($"GetInventoryById-{id}");

    int itemsInStock =
        await cachePolicy.ExecuteAsync(context => GetItemsInStockCount(), policyExecutionContext);

    async Task<int> GetItemsInStockCount()
    {
        HttpResponseMessage response = await httpClient.GetAsync(requestEndpoint);

        if (response.IsSuccessStatusCode)
        {
            int itemsInStockCount = await response.Content.ReadAsAsync<int>();
            return itemsInStockCount;
        }

        return 0;
    }

    return Ok(itemsInStock);
}

The first few lines are straight forward, setup the endpoint, get the HttpClient, get the cache policy. Like in the previous post, I use the context when placing items into the cache and retrieving them.

Because I want to cache the value inside the HttpResponse (and not the response itself) I can’t call the HttpClient from inside the policy’s exec method. Instead I need to call something that returns the int from inside the HttpResponse.

The easiest way of doing this is to use a local function which makes the HttpClient request, deserializes the response and returns the int from the response.
In this post I am assuming that all values inside the response should be cached, I am NOT checking the status code of the response.

The policy then caches the int for the period specified in Startup.

That’s all there is to it.

If you are wondering how to selectively cache values inside the HttpResponse, tune in for the next post in this series.

Full source code here.

Selectively Caching a HttpResponseMessage with Polly – caching series 1/3

Full source code here.

When I give talks on Polly I show how to use it in a Web API application that calls another Web Api application. I give a simple example of how to use the cache policy where I store the whole of the HttpResponseMessage. At the end of the talk I often get a couple of questions –

1. is it possible to cache the response only when the status code is in the 200 range.
2. is it possible to cache the values inside the response instead of the whole response.

The answer to both of these is yes, and in this series of three articles I will explain how to do both of these things, and how how to combine them to cache a value inside a response only if the response is in the 200 range.

This article will demonstrate how to selectively cache HttpResponseMessages based on the Http StatusCode of the response. The second will show how to cache values inside the HttpResponseMessage, and the third will show how selectively cache values inside the HttpResponseMessage.

As described in an earlier post, using a cache policy is a little more involved than using other policies. See this post for more info.

Changes in Startup
In Startup inside ConfigureServices I setup the memory cache, the HttpClientFactory and a policy registry (I’m not going to go into a detailed explanation of this code as it is already explained in the earlier article and you have all the source code).

All the action for this post takes place in the Configure method.

Creating the cache filter
The cache timeout filter, it sets the length of time to cache a value. The filter here will cache a response for 10 seconds if the response indicates a success, otherwise it caches the response for 0 seconds, in this case the Polly code does not perform any caching.

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
    IAsyncCacheProvider cacheProvider, IPolicyRegistry<string> registry)
{
    Func<Context, HttpResponseMessage, Ttl> cacheOnly200OkFilter =
        (context, result) => new Ttl(
            timeSpan: result.StatusCode == HttpStatusCode.OK ? TimeSpan.
            slidingExpiration: true
        );

The cache policy says that it caches HttpResponseMessages and uses the filter to decide if a response should be cached.

IAsyncPolicy<HttpResponseMessage> cacheOnlyOkResponsePolicy =
    Policy.CacheAsync<HttpResponseMessage>(
        cacheProvider.AsyncFor<HttpResponseMessage>(), //note the .AsyncFor<HttpResponseMessage>
        new ResultTtl<HttpResponseMessage>(cacheOnly200OkFilter),
        onCacheError: null
    );

Note the AsyncFor, this is very important. Thanks to Dylan Reisenberger for his help here, I spent too many hours trying to figure the overloads with no success.

Try it out in the provided solution, hit F5 and put some breakpoints in the controllers and on the filter in Startup.

That’s it, you now have selective caching of responses.

In the next post, I’ll show you how to cache the value inside the response instead of the whole response.

Full source code here.