Syndication IconNew article alerts are available via Atom. Hide this message

Fail Silently with Memcache Client

For web applications caching is king and I've recently been playing with memcached to cache the results of expensive queries in a Rails application. As a client I've chosen Seattle RB's memcache-client.

The memcache-client library is rather lovely, but it does seem to have the opinion that if a memcached instance fails it should throw an exception which your code has to deal with. I don't agree with that: when a cache fails it doesn't matter. Either the application can continue running in an uncached mode - slow, but possible - or there are other memcache instances that can be used. Switching to either of these should require no special effort in code that uses the library.

Ruby, being awesome, lets me change the behaviour of the client library very easily. Monkey patching may be frowned upon, but it does have a use.

# A simple monkey-patch of MemCache so that broken memcached instances don't 
# cause fatal errors in the application. Performance may be severaly degraded
# but it should be possible to use the app anyway!
# 
# A typical use would look something like:
# 
#   result = if cache.alive?
#     fetch = cache.get(:foo)
#     if !fetch
#       fetch = calculate(:foo)
#       cache.set(:foo, fetch)
#     end
#     fetch
#   else
#     calculate(:foo)
#   end
# 
class MemCache
  # Does the cache configuration contain any memcached instances that can 
  # currently be used?
  # 
  # Author: Conor Curran [http://forwind.net/]
  # 
  def alive?
    !!cache.servers.detect{ |s| s.alive? }
  end

  # Rescue from MemCache::MemCacheError -- we want the cache to fail silently
  # (at least from the point of view of the application - you should still
  # monitor memcached).
  # 
  def get_with_rescue(*args)
    get_without_rescue(*args)
  rescue MemCache::MemCacheError
  end
  alias_method :get_without_rescue, :get
  alias_method :get, :get_with_rescue
  alias_method :[], :get
  
  # Rescue from MemCache::MemCacheError -- we want the cache to fail silently
  # (at least from the point of view of the application - you should still
  # monitor memcached).
  # 
  def set_with_rescue(*args)
    set_without_rescue(*args)
  rescue MemCache::MemCacheError
  end
  alias_method :set_without_rescue, :set
  alias_method :set, :set_with_rescue
  alias_method :[]=, :set
  alias_method :add, :set

  # Rescue from MemCache::MemCacheError -- we want the cache to fail silently
  # (at least from the point of view of the application - you should still
  # monitor memcached).
  # 
  def delete_with_rescue(*args)
    delete_without_rescue(*args)
  rescue MemCache::MemCacheError
  end
  alias_method :delete_without_rescue, :delete
  alias_method :delete, :delete_with_rescue
end

Leave feedback...

  1. Would this not have been as easily implemented with either inheritance (a subclass) or delegation (a wrapper class) to catch the exception?

  2. @Johan I don’t see either as an easier option than mine but if it works for you then awesome, go for that.

Commenting is closed for this article.

About the boy

A picture of Craig in grayscale

Hi, I'm Craig and I'm a Ruby coder. I live, work and play in London. I like scaling applications and eating yoghurt. Sometimes I climb rocks. Most of the time I climb back down.

You can contact me by email, MSN or Jabber. My address on all of these is craig@xeriom.net.

Licence

The entire content of this blog is public domain. Use it however you fancy. You don't even need to attribute it to me, although it would be nice if you did. Just don't sue me and we'll all be happy.

Interesting Blogs

I Work With Rails

Recommend Me

My Travels

I go places. Do you go places too? Let's meet up!.