mperham/girl_friday

Can't get Redis store to work

Closed this issue · 16 comments

I've added the following to my redis.rb initializer:
uri = URI.parse(ENV['REDISTOGO_URL'] || 'redis://localhost:6379')
$redis = Redis.new(host: uri.host, port: uri.port, password: uri.password)

and the following to my girl_friday.rb initializer:

SYNC_FRIENDS_QUEUE = GirlFriday::WorkQueue.new(:sync_friends, size: 2, store: GirlFriday::Store::Redis, store_config: [{ redis: $redis }]) do |msg|
Account.sync_friends(msg[:account_id])
end

However, when I push stuff to the queue (SYNC_FRIENDS_QUEUE.push(account_id: account.id))), it gets processed in memory. Tailing the Redis log shows no connected clients. Only when I do GirlFriday.status can I see the Redis client connected. Am I configuring something wrong?

You have to connect Redis after Unicorn forks. Check out http://j.mp/nu4zRR and see if that helps.

Are you able to get it working locally with the Redis store?

Redis.connect(url: ENV["REDISTOGO_URL"]

would work too, as connect can take a url option which will be automatically parsed.

Thanks for the pointer. I added the following to my config/unicorn.rb file:

require 'redis'

after_fork do |server, worker|
$redis = Redis.connect(url: ENV['REDISTOGO_URL'] || 'redis://localhost:6379')
end

However, the queue still processes in memory. Only when I run GirlFriday.status from the console clients connect to Redis in the log.

ok, I'll try to repro soon.

Any luck reproing this yet?

@fbjork I'm not able to reproduce. Is your app set up like this? And to clarify, are you just having problems on Heroku or local too? What command are you running? unicorn -c unicorn.rb is what I'm using & I verified that the store is Redis.

Yep, using the new connect method worked! This is using the latest commit from master.

However, when I run GirlFriday.status I just get {} returned. Bug?

What's good place to configure the $redis variable so I can access it from the Rails console? Since the $redis variable is only set in config/unicorn.rb it isn't set in the console.

Wouldn't $redis be nil there anyway? Given it's set in the after_fork block inside config/unicorn.rb?

heh, yeah, duh... I suppose you could set it in an initializer or environment file if it doesn't already exist?

$redis = Redis.connect unless $redis

?

Ok, that worked. However on heroku I get this error:

 irb(main):009:0> GirlFriday.status
Errno::ECONNREFUSED: Connection refused - Unable to connect to Redis on 127.0.0.1:6379
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis/client.rb:236:in `rescue in establish_connection'
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis/client.rb:222:in `establish_connection'
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis/client.rb:23:in `connect'
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis/client.rb:247:in `ensure_connected'
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis/client.rb:137:in `block in process'
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis/client.rb:206:in `logging'
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis/client.rb:136:in `process'
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis/client.rb:46:in `call'
    from /app/vendor/bundle/ruby/1.9.1/gems/rpm_contrib-2.1.4/lib/rpm_contrib/instrumentation/redis.rb:25:in `block in raw_call_command_with_newrelic_trace'
    from /app/vendor/bundle/ruby/1.9.1/gems/newrelic_rpm-3.1.2/lib/new_relic/agent/method_tracer.rb:242:in `trace_execution_scoped'
    from /app/vendor/bundle/ruby/1.9.1/gems/rpm_contrib-2.1.4/lib/rpm_contrib/instrumentation/redis.rb:23:in `raw_call_command_with_newrelic_trace'
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis.rb:301:in `block in llen'
    from /usr/local/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-2.2.2/lib/redis.rb:300:in `llen'
    from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.5/lib/girl_friday/persistence.rb:41:in `size'
    from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.5/lib/girl_friday/work_queue.rb:54:in `status'
    from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.5/lib/girl_friday.rb:43:in `block in status'
    from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.5/lib/girl_friday.rb:41:in `each'
    from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.5/lib/girl_friday.rb:41:in `inject'
    from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.5/lib/girl_friday.rb:41:in `status'
    from (irb):9
    from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.0.9/lib/rails/commands/console.rb:44:in `start'
    from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.0.9/lib/rails/commands/console.rb:8:in `start'
    from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.0.9/lib/rails/commands.rb:23:in `<top (required)>'

I've set the following in config/unicorn.rb

after_fork do |server, worker|
$redis = Redis.connect url: ENV['REDISTOGO_URL']
end

Any ideas?

I'm actually seeing that too. A restart did not help. I actually wonder if using a global $redis might be a very bad idea? @mperham have any thoughts on this? From the little bit I've found, maybe globals aren't always global, especially when dealing with threads?

@fbjork I just switched over to using connection_pool this evening instead of vanilla Redis instances. I'd love to get some feedback on how it works on Heroku. I'll be switching my app to using it tonight.

Sure, how should the configuration look like given I use unicorn?

I actually removed the after_fork block from unicorn.rb & just configured it in my app, something like this:

require 'redis'
require 'connection_pool'

$redis = ConnectionPool.new(size: 4).new{ Redis.connect(url: ENV["REDISTOGO_URL"]) }
Q = GirlFriday::WorkQueue.new(:foo, store: GirlFriday::Store::Redis, store_config: { pool: $redis } )

I tested it out on Heroku & it worked. I'm going to close this for now, but if you have more problems please open another ticket. Thanks for all your testing, we really appreciate it!

I guess you meant to put:
$redis = ConnectionPool.new(size: 4) { Redis.connect(url: ENV["REDISTOGO_URL"]) }

When I tried to run GirlFriday.status I get this now:

LocalJumpError: no block given (yield)
from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.6/lib/girl_friday/persistence.rb:56:in block in redis' from /app/vendor/bundle/ruby/1.9.1/gems/connection_pool-0.1.0/lib/connection_pool.rb:41:inwith'
from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.6/lib/girl_friday/persistence.rb:55:in redis' from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.6/lib/girl_friday/persistence.rb:44:insize'
from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.6/lib/girl_friday/work_queue.rb:55:in status' from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.6/lib/girl_friday.rb:43:inblock in status'
from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.6/lib/girl_friday.rb:41:in each' from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.6/lib/girl_friday.rb:41:ininject'
from /app/vendor/bundle/ruby/1.9.1/gems/girl_friday-0.9.6/lib/girl_friday.rb:41:in `status'

Please file a new issue & I'll take a look asap.