Booko – now with better fragment caching!

One of the more processor intensive sections on the Booko site is the “Most Viewed” section. This section is generated by finding all the books which have been viewed in the last 7 days, and ranking them by their frequency. This query can take up to 1.6 seconds according to Benchmark.realtime {}. I had set up fragment caching for this, but every time a book is viewed, Booko notes down the ISBN and the time, then, because the data has changed, goes and recalculates the most popular book again. So the caching really isn’t helping anyone who’s looking at books – it may help someone who’s on the front page, but that’s it.

Ideally I wanted this section of HTML to have a time based expiry but that functionality isn’t part of the regular Rails caching system and I don’t want to install plugins to do this for me. After a bit of searching, Google found me a very relevant page which discussed the issue I was facing.

The goal is for a time based expiry – let’s say 15 minutes or 900 seconds. When you call the cache function, you pass in some data to help it create a unique key for the HTML being cached. If that name already has some cached HTML associated with it, that HTML will be rendered rather than generating the HTML again. Previously, I was just naming this cache “Popular” – the code looked like this:
[sourcecode language=’ruby’]
<% cache("Popular") do %>
# Generate the list of most popular books
# Print out the popular books
<% end %>
[/sourcecode]
Instead, we’ll do this:
[sourcecode language=’ruby’]<% cache(["Popular", Time.now.to_i / 900 ].to_s) do %>
# Generate the list of most popular books
# Print out the popular books
<% end %>[/sourcecode]
This version will append a number to the cache key which will change every 900 seconds, or 15 minutes. Here’s what it generates as a key:

>> ["Popular", Time.now.to_i / 900 ].to_s
=> "Popular1369073"

So, now we have a new key for the cache every 15 minutes. When the key changes, the cache system won’t be able to find the HTML and will regenerate it. This would be a terrible idea if you’re using file based caching BTW, since you’d be constantly creating new cache files. However, if you’re using memcached, like Booko does, you’re home free. Memcached automatically expires objects from its cache using an LRU algorithm. So, with any luck, Booko’s performance should improve.