It is always caching!

five keyboard keys on a black surface spelling out the work cache

In October I added multiple account deletion options to the Costs to Expect API – you can delete your data for a specific App, reset your data for one of our Apps or delete your account entirely.

There could be a large amount of data to delete so I decided to handle the deletes behind the scenes with jobs. This worked well and during all my testing, there was never an issue. If an issue does occur a notification gets sent and I can fix the issue.

However, after release, I tested with a throwaway account, and it wasn’t working. As a user I could reset my state but when I signed in again all my data was still showing.

For a little while I was perplexed. The API wasn’t erroring, the data was being removed but Budget still showed the old state. The first hint happened when I tried to do something in Budget; I immediately got an error from the API, a budget item couldn’t be created because the resource didn’t exist.

Aha! I knew what the problem was. I said to myself, “Budget has data, the API doesn’t, there must be a cache issue somewhere.

Budget doesn’t retain a cache so it can only be the API. I rush (really, I did) to my IDE and low and behold, my jobs don’t clear the cache after deleting the requested data – oops!

How did this happen?

Well, that’s easy. During development, I turn off the cache on my local instance of the API as I don’t want the cache getting in the way of any new features I’m writing or debugging. I test before I make a new release, manually and automatically. Though clearly, I’m not always turning cache back on.

The Solution

The solution is easy – do a better job of testing but it isn’t quite as simple as that. I’m going to update my automatic tests to include testing with and without caching enabled. More importantly though, I’m going to expose the API cache status.

It isn’t unusual for the development or staging version of your Apps to highlight their status – a bar at the top, a different background, a visual notifier of some kind. I’m going to update Budget and all the other Costs to Expect Apps to include this notifier and show the state of the API, is caching enabled? Is it in debug mode? That way when I’m testing a data state feature, I’m more likely to spot that status and think about the extra steps.

Website caching, simple now, later, dependant caches.

Two weeks ago, I quickly added caching to the Costs to Expect Website. My goal was to reduce the number of unnecessary API requests the Website made to the Costs to Expect API, mission accomplished.

The problem, I did a quick job, improvements needed.

The Costs to Expect Website is a long term social experiment, my wife and I are tracking the total cost of raising humans; we want to know how far off the £250,000 per child figure we will be when our sons reach the age of 18.

Back to the caching, issue one, I added caching to the top four or five pages; the rest of the Website needs some love. Issue two, for some unknown reason, I decided 15 mins was a sensible cache lifetime.

Solution one

I hacked in the caching; I added a simplified version of the much more featureful caching in the Costs to Expect App. I need to refactor the ‘request’ code and add caching for all requests.

Solution two

I set the cache lifetime at 15 minutes, why I don’t know. The content on the Website changes at most daily and additionally there is no need for the data to be live; people are not going to ‘throw a fit’ if they can’t see the latest expense we have added for Jack or Niall.

I am going to set the cache lifetime to four hours.

Four hours you say, why not 24? Well, I figured it is a sensible limit to ensure there isn’t too much of a mismatch between cached data while still dramatically reducing API requests.

Imagine a scenario whereby a user browses to the site and visits the summary page; the results are cached; they never, however, make it to the lists for that summary. If a second user comes along three hours later and views the listings, there is a good chance the data will mostly match the cached summary. If I set the cache lifetime at 24 hours, a value that initially seems reasonable, I am increasing the chance of the summaries and data mismatching.

There is a solution to the inconsistent data problem, dependant caches.

I need to add support for linking cached data, for example, a summary and the related lists, and more importantly, controlling the maximum period allowable between dependant cache item creation.

With the current implementation, there can be a difference of up to four hours between summary and list cache creation, realistically, the limit for dependant data should be closer to five minutes.

I will eventually update the caching system for the Costs to Expect App and at some point, trickle the implementation down to the Costs to Expect Website.