Skip to content

Rails caching: expiration silently fails when called from the console or rake tasks

By Paul Leader

I have an application where a lot of work gets done behind the scenes by worker processes, scripts and rake tasks. I have a sweeper for one of my models to clear out some caches that can’t be cleared automatically using DHH’s key-based expiration technique. The cache keys in this use case are simple strings.

The expiration code looks like this (for the “Antibody” model)…

# Expire the sitemap page for this antibody
# Antibodies are grouped into a maximum of 1000 based on their ID
page = (antibody.id / 1000).floor
expire_fragment "sitemap/antibodies/#{page}"

When modifications are made to an item in the context of a controller the cache expiration is just fine.

However when an antibody is updated on the console the code runs, throws no exceptions, logs nothing, it simply fails silently. The cache is not expired, but no indication is given for why.

It turns out that the expires_fragment method expects to have a @controller instance method, and if it doesn’t it simply does nothing, the same appears to be the case for expire_action and expire_page. This kind of makes sense, sweepers have been designed to be mainly triggered from controller actions, however it’s frustrating if you have a lot of background processing going on.

The issue can be easily fixed in sweepers that use expires_fragment by including the following…

@controller ||= ActionController::Base.new

The silent failure seems like the worst of all possible failure modes. At a minimum a warning in the logs would be nice, throwing an exception would be better, and actually handling this situation would be best.

I’ve filed a bug report for Rails, and I’m planning to implement a fix in the near future, but for the meantime putting the line above in your sweeper should solve your problem.