Search code examples
ruby-on-railsrubyherokuredisworker

Redis connection refused through ruby daemon worker on Heroku


A Rails 3.2.6 application running as a 'web' Heroku process is connecting to Redis using the ENV["REDISTOGO_URL"] environment variable:

irb(main):002:0> Redis.current
=> #<Redis client v2.2.2 connected to redis://xxx.redistogo.com:1234/0 (Redis v2.4.11)>

----- /initializers/redis.rb

if Rails.env.development?
  Redis.current = Redis.new
elsif Rails.env.test?
  Redis.current = Redis.new
elsif Rails.env.production?
  uri = URI.parse(ENV["REDISTOGO_URL"])
  Redis.current = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
end

A ruby daemon 'streaming' process runs as a secondary worker:

----- Procfile

web: bundle exec rails server thin -p $PORT -e $RACK_ENV
worker: bundle exec rake jobs:work
streaming: RAILS_ENV=production ruby bin/streaming.rb start

However, the streaming process is crashing when it calls methods in the main Rails application that connect with Redis - even though the streaming process supposed to be loading the same redis.rb initializer as the 'web' Rails application process.

----- /bin/streaming_ctl.rb

# encoding: UTF-8

require "rubygems"
require "bundler/setup"
require "daemons"

Daemons.run(File.expand_path("../streaming.rb", __FILE__))

----- /bin/streaming.rb

# encoding: UTF-8

# TODO: set rails env in init script
ENV["RAILS_ENV"] ||= "production"

# load rails environment
require File.expand_path('../../config/environment', __FILE__)

logger = ActiveSupport::BufferedLogger.new(File.expand_path("./../../log/streaming.log", __FILE__))

Streaming.start
logger.info("\nStarting streaming in #{Rails.env.to_s} mode.")

Why is the streaming process/worker using the default Redis host and port?

[streaming.1]: /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis/client.rb:236:in `rescue in establish_connection': Connection refused - Unable to connect to Redis on 127.0.0.1:6379 (Errno::ECONNREFUSED)

Solution

  • Switching from "Redis.current" in /initializer/redis.rb and using a "$redis" variable convention instead (as illustrated here http://jimneath.org/2011/03/24/using-redis-with-ruby-on-rails.html) fixed the connection problem.

    The app was using redis gem version 2.2.2 at the time. It appears as though the Redis.current in this gem version won't be consistent across 'web' and 'worker' processes because Heroku runs these processes on separate threads. The documentation on the gem repo suggests that updating to gem to >= version 3 will enable Redis.current to run in multi-threaded environments:

    https://github.com/redis/redis-rb/blob/master/CHANGELOG.md#300