Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restarting Rails Redis Cache Store connection upon Passenger fork

I want to use redis cache store (using redis-store gem).

It works fine locally but when going on production where Passenger forks multiple instances of Rails workers we're getting Redis errors which indicate synchronization problems between the different instances regarding Redis access.

An example for such an error is

 Got '7' as initial reply byte. If you're running in a multi-threaded environment, make sure you pass the :thread_safe option when initializing the connection. If you're in a forking environment, such as Unicorn, you need to connect to Redis after forking.
  redis (2.2.2) lib/redis/connection/ruby.rb:78:in `format_reply'

I have done some reading and learned that each Passenger worker instance must create its own Redis connection. This might be implemented using the following code

#config/initializers/redis_fork_init.rb
if defined?(PhusionPassenger)
  PhusionPassenger.on_event(:starting_worker_process) do |forked|
    if forked
      $redis = Redis.new
    end
  end
end

Assuming Redis access is done through $redis all over the code - this solution is great.

My question is - how can I create a new Redis connection that will be used when I do Rails.cache operations such as read, write etc... ?

my config/environments/production.rb includes the following:

config.cache_store = :redis_store, { :host => 'localhost', :port => 6379, :thread_safe => true } 

Using Rails 3.2.3, Redis 2.2.2, redis-store 1.1.1, Passenger 3.0

like image 902
Erez Rabih Avatar asked Jul 08 '12 13:07

Erez Rabih


2 Answers

Take a look on reconnect method of redis store: https://github.com/jodosha/redis-store/blob/master/redis-activesupport/lib/active_support/cache/redis_store.rb

So basically your fork block should look like:

if defined?(PhusionPassenger)
  PhusionPassenger.on_event(:starting_worker_process) do |forked|
    if forked
      Rails.cache.reconnect
    end
  end
end
like image 149
Tor Avatar answered Oct 26 '22 19:10

Tor


Adding to @Tor's response, change $redis = Redis.new to Rails.cache.reconnect.

Info found in this github issue, https://github.com/jodosha/redis-store/issues/21#issuecomment-948569

like image 34
anthonyfojas Avatar answered Oct 26 '22 19:10

anthonyfojas