Fredrik Forssen - 428 - Jun 24, 2014

What kind of caching strategy do you use with ServiceStack?

Say for example that I have a service that recieves two types of messages, one that creates blogposts and one that searches blogposts by title fragment. Obviously I would like to cache results for searches that are made, but since they are made by a name fragment it gets hard to construct a good cache key that can be invalidated when a new blogpost is posted?

If I use a MemoryCacheClient I do have some more options in the form of “RemoveByPattern” and “RemoveByRegex”, but then I’m locked in to having my cache in memory and can’t switch to for example Redis once I’m in a production environment since those methods only seem to exist on the MemoryCacheClient.

Also, even having these, generating all possible fragments from a potentially long blogpost title and throwing each possible fragment into the RemoveByPattern method seems a bit of a hack to me :confused:

I could just invalidate the entire cache of old searches on each new blogpost (and maybe that is actually the best way to go here?), but that seems like a very blunt tool.

So, how do you structure your cache to get the maximum advantage out of it? Does anyone have any best practices or good advice from the trenches? :slight_smile:

Searches are basically hard to invalidate since when you modify a record it’s very hard (impossible?) to work out what caches needs invalidating, which is why using a Search Index like Lucene/ElasticSearch is generally the preferred approach as searches are cheap and documents can be modified at runtime. If using an index isn’t an option then caching by expiry time is a good alternative for searches. 

If you can’t identify the record (i.e. with a PK) a good key to cache with is just to use the pathInfo + queryString. The Redis CacheClient also implements IRemoveByPattern with the glob pattern described in: http://redis.io/commands/keys

As for cache strategies I had a separate “Cache Service” layer which was responsible for constructing and invalidating caches when it was notified when entities changed. Because it was responsible for constructing all the caches, it new what caches needed to invalidated.

I also like DHH’s key-based caching strategy described in:
https://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works