Kubernetes, Rails and Memcached

Jan 28, 2018 14:28 · 403 words · 2 minutes read kubernetes rails memcached dalli

I wanted to use a pool of memcached servers to back my rails cache. The dalli wiki describes a Heroku setup that uses environment variables to configure a list of memcached servers. This is exactly what I want when deploying to Kubernetes. Using environment variables allows me to avoid hardcoding the memcached host names into the application configuration code.

However, when I set my cache_store to :dalli_store rails defaults to the FileCache. What the heck? When I use :mem_cache_store as described in guides.rubyonrails.org the memcached servers variable does not get populated. What the heck?

I read through the rails configuration and application bootstrapping process in order to get the config object just right. The solution I came up with uses the expected environment variable (MEMCACHE_SERVERS) but uses the appropriate cache_store which is rails 5 friendly.

config.cache_store = :mem_cache_store, ENV['MEMCACHE_SERVERS'].split(',')

In Detail

The config object defines cache_store as an attr_accessor (which means the function cache_store= is defined automatically). Here is an example of what we’re dealing with:

class Config
  attr_accessor :cache
  def initialize
    @cache = ['abc','def']
  end
end

irb(main):015:0> a = Config.new
=> #<Config:0x007f8d9b8a2ac0 @cache=["abc", "def"]>

irb(main):018:0> a.cache = 'hello', 'world'
=> ["hello", "world"]

irb(main):020:0> a.cache
=> ["hello", "world"]

Now that we know how the cache_store instance variable is defined, we need to know what happens to it.

Rails has a bootstrap process that runs after all the configuration setting happens. Near the beginning of the bootstrap process, ActiveSupport::Cache.lookup_store is invoked.

That function uses the first value in the cache_store array as the lookup symbol and the rest of the array as arguments to the constructor.

At this point it became clear that :dalli_store is not defined and will not be found so we will end up with the default FileStore.

However, if :mem_cache_store is used, we can see that the dalli documented environment variable MEMCACHE_SERVERS are no where to be found.

We end up combining approaches and using the environment variable we expect with the store symbol that rails expects.

Afterthought

When I first wrote this I used a splat on the memcached servers (with a *). But after writing up exactly what happens and tracing the code, I found out I don’t need to do that. Blogging at its best.

Also I am not a rails expert and am simply trying to get stuff done with rails. I would love to be shown a better/cleaner/simpler way of solving this if it exists.