Join the Stack Overflow Community
Stack Overflow is a community of 6.7 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I am using redis as a read cache. I have created an initializer

config/initializer/redis.rb

$redis = Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])

I am using this global in my unicorn.rb to create a new connection whenever a new worker is created.

before_fork do |server, worker|
  # clear redis connection
  $redis.quit unless $redis.blank?
end

# Give each child process its own Redis connection
after_fork do |server, worker|
  $redis = Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])
end

I am also using this global variable whenever I need to access my redis servers. But I am not comfortable using this global variable. Are there any better options than using global variable?

share|improve this question
5  
stackoverflow.com/a/16474679/19079 answers this better than any of the answers below. – tomtaylor May 14 '14 at 21:34
up vote 28 down vote accepted
+50

expanding further on mestachs suggestion, namespacing a module in your initializer as below

config/initializers/redis.rb

module ReadCache
  class << self
    def redis
      @redis ||= Redis.new(:url => (ENV["REDIS_URL"] || 'redis://127.0.0.1:6379'))
    end
  end
end

then in unicorn.rb

 before_fork do |server, worker|
    ...
   if defined?(ReadCache.redis)
    ReadCache.redis.quit
   end
    ...
 end

 after_fork do |server, worker|
    ...
   if defined?(ReadCache.redis)
    ReadCache.redis.client.reconnect
   end
    ...
 end
share|improve this answer
    
So, if I have thousand unique requests simultaneously, I would also need thousand connexions to the redis server, right? – yeyo Feb 13 '14 at 1:11
    
@Kira Can you explain a bit more. I dont think it will need thousand connections. If I understand correctly, This module will be common to the whole app. – Anirudhan J Feb 14 '14 at 14:28
1  
this article devcenter.heroku.com/articles/… helps alot with understanding connection pooling weather or not your using Heroku. with a bit of understanding from that you can them tune your sidekiq concurrency see: github.com/mperham/sidekiq/wiki/…. – blotto Feb 14 '14 at 18:03
    
@blotto that was a nice reading, thank you. Although, your sample code it's not using ActiveRecord (correct me if I'm wrong), so the pooling technique it's not being used and still we have a redis connection per client/worker. – yeyo Feb 16 '14 at 3:44
    
@Kira, it really depends on your setup. my example presumes ActiveRecord (Rails), and a forking server such as Unicorn. there would actually be more than one connection per dyno/worker. Calculating concurrency, and ultimately defining such settings, is a balance between your allowed db connections, and how much you want to scale. – blotto Feb 16 '14 at 5:32

There is Redis.current, which you can use to store your one-and-only Redis instance.

So instead of using $redis, you can assign your instance as follows:

Redis.current = Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])

Redis.current was introduced to redis-rb in 2010 as a standard way to grab a redis connection, so I was surprised that no other answer mentioned it.

share|improve this answer
1  
this should be accepted answer – Dr.Strangelove Mar 7 '16 at 2:44

if you don't already use another Rails.cache I advise you to just use that mechanism with redis.

The gem redis-store makes this realy easy (https://github.com/redis-store/redis-store)

This way you can just do Rails.cache.reconnect and all is dandy

https://github.com/redis-store/redis-store/issues/21#issuecomment-948569

It also allows you to use the awesome Rails.cache API, which has some neat features: http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html

share|improve this answer

A more namespaced option to replace your global variable, you can create a method in a module

module Caching
  def self.redis
    ... initialize/memoize/reconnect here...
  end
end

You than then call it with:

Caching.redis

share|improve this answer

According to this Heroku, you don't need to add $redis to your Unicorn:

No special setup is required when using Redis Cloud with a Unicorn server. Users running Rails apps on Unicorn should follow the instructions in the Configuring Redis from Rails section and users...

Here's all the "Configuring Redis from Rails section" has for before Rails 4 (besides the Gemfile and some other pre-Rails 3 stuff):

# config/initalizers/redis.rb

if ENV["REDISCLOUD_URL"]
  uri = URI.parse(ENV["REDISCLOUD_URL"])
  $redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
end

It doesn't really give an explanation as to why "no special setup is required".

share|improve this answer
1  
I know that you do need to do something special. I have maxed out 512 connection redis cloud instances on production heroku servers using unicorn. – Aeramor Sep 25 '14 at 23:42

try this out:-

you can use constant instead of global variable.like in config/initializer/redis.rb

REDIS = Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])

and in unicorn.rb

before_fork do |server, worker|
  # clear redis connection
  REDIS.quit if defined?(REDIS)
end

# Give each child process its own Redis connection

after_fork do |server, worker|
  REDIS ||= Redis.new(:host => ENV["REDIS_HOST"], :port => ENV["REDIS_PORT"])
end
share|improve this answer
    
sounds interesting, what is the role of this constant? I mean, it's not a global variable but it behaves similar as if it were a global variable. – yeyo Feb 13 '14 at 1:05

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.