Find file
Fetching contributors…
Cannot retrieve contributors at this time
106 lines (82 sloc) 3.36 KB


  • Ruby EventMachine memCACHED client implementation
  • provides a direct interface to the memcached protocol and its semantics
  • uses the memcached binary protocol to reduce parsing overhead on the server side (requires memcached >= 1.3)
  • supports multiple servers with simple round-robin key hashing (TODO: implement the libketama algorithm) in a fault-tolerant way
  • writing your own abstraction layer is recommended
  • uses RSpec
  • partially documented in RDoc-style


Each request may be passed a callback. These are not two-cased (success & failure) EM deferrables, but standard Ruby callbacks. The rationale behind this is that there are no usual success/failure responses, but you will want to evaluate a response[:status] yourself to check for cache miss, version conflict, network disconnects etc.

A callback may be kept if it returns :proceed to catch multi-response commands such as STAT.

remcached has been built with fault tolerance in mind: a callback will be called with just {:status => Memcached::Errors::DISCONNECTED} if the network connection has went away. Thus, you can expect your callback will be called, except of course you're using quiet commands. In that case, only a "non-usual response" from the server or a network failure will invoke your block.

Multi commands

The technique is described in the binary protocol spec in section 4.2. Memcached.multi_operation will help you exactly with that, sending lots of those quiet commands, except for the last, which will be a normal command to trigger an acknowledge for all commands.

This is of course implemented per-server to accomodate load-balancing.


First, pass your memcached servers to the library:

Memcached.servers = %w(localhost localhost:11212 localhost:11213)

Note that it won't be connected immediately. Use Memcached.usable? to check. This however complicates your own code and you can check response[:status] == Memcached::Errors::DISCONNECTED for network errors in all your response callbacks.

Further usage is pretty straight-forward:

Memcached.get(:key => 'Hello') do |response|
  case response[:status]
    when Memcached::Errors::NO_ERROR
      use_cached_value response[:value] # ...
    when Memcached::Errors::KEY_NOT_FOUND
      refresh_cache! # ...
    when Memcached::Errors::DISCONNECTED
      proceed_uncached # ...
      cry_for_help # ...
Memcached.set(:key => 'Hello', :value => 'World',
              :expiration => 600) do |response|
  case response[:status]
    when Memcached::Errors::NO_ERROR
      # That's good
    when Memcached::Errors::DISCONNECTED
      # Maybe stop filling the cache for now?
      # What could've gone wrong?

Multi-commands may require a bit of precaution:

Memcached.multi_get([{:key => 'foo'},
                     {:key => 'bar'}]) do |responses|
  # responses is now a hash of Key => Response

It's not guaranteed that any of these keys will be present in the response. Moreover, they may be present even if they are a usual response because the last request is always non-quiet.