1

My team and I are currently maintaining a caching system that is purely based on keys. From what I've read we are striving for a system that's based on the cache-aside strategy. Where we have a website that talks to a rest service using httpclients. These clients make use of a memory cache which works based on a combined key. When another method is called that would invalidate a cache item, we havez to manually instruct the memorycache to remove it.

Let me explain by example.

MemoryCacheStore => object stored in a singleton for the entire webapplication (Asp.Net MVC)

Pseudo code explaining the case:

public class CustomerRestClient {
    private readonly IMemoryCacheStore _cacheStore;
    private readonly User user;
    public CustomerRestClient(IMemoryCacheStore cacheStore, User user){
        _cacheStore = cacheStore;
        _user = user;
    }

    public Customer Get(int id){
        return _cacheStore.Get($"Customer-Get-{id}-{_user.Id}", TimeSpan.FromMinute(10), () => RestService.Get(id));
    }

    public Customer Update(Customer customer){
        var newCustomer = RestService.Update(customer);
        _cacheStore.InvalidateKey($"Customer-Get-{customer.id}-{_user.Id});
        return newCustomer;
    }
}

The problem with this approach is that the developer needs to know which keys to invalidate whenever an object has changed. We are considering trying to solve this with some kind of cachekeymanager to eliminate the key string magic but imho it doesn't solve the problem that the developer still needs to know what to invalidate when and these definitions are spread out throughout all of our restclients.

You might argue that this shouldn't be a problem and I must admit in the beginning this wasn't. But as the codebase grows larger, objects change name, this is becoming a management nightmare with several bug reports as the result.

So my question is;
Do you know of any caching strategies or frameworks I can look into which may resolve our case?

I'm thinking more in the direction of defining a dependency graph and I'm hoping someone has already tackled this problem which may give us new insights.

  • 2
    The two most difficult problems in software development: cache invalidation, naming things, and off-by-one errors. – Robert Harvey Mar 7 '18 at 19:29
1

What you are striving for is a local database like layer.

Currently you are storing results for multiple actions (API calls), and you struggle to uniquely name such actions as keys.

Thinking with a database or object store mindset, You need to store the entities/objects that are created, changed or removed as the result of these actions. And you need to uniquely address the objects via a combination of: Type, Id. You also need to identify stale objects based on Timestamp.

There are many offline sync-able, embed-able DB solutions that follow such approach, for example: http://parseplatform.org/ or https://pouchdb.com/ etc. These behave as smart object caches.

As far as the problem of "remember to invalidate the cache" is concerned, you can decouple Object modifying code from the Cache using event pattern:

  1. API calls that modify data, emit new, changed, or removed objects as change events. Each event has: Type, Id, timestamp, and latest object/data. Developers writing such API calls only need to emit all the objects changed. No need to directly call cache invalidation.

  2. Cache subscribes to these events and syncs the local object db/store.

  3. API calls that need to get an object, query the cache first by specifying object type, id and timestamp. If cache object not exist or is stale, network call is made and object is emitted as event.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.