I have a Rails (web) app that I need to add a (redis) pub/sub subscriber too.
Below is my PubsubSubscriber class which I need to kick off then the app starts up.
The redis connection is created in a resque.rb initializer file. I tried PubsubSubscriber.new after the connection, but when I try to start the rails server it hangs at:
=> Booting Thin
=> Rails 3.2.13 application starting in development on http://0.0.0.0:5000
=> Call with -d to detach
=> Ctrl-C to shutdown server
As opposed to when the server starts successfully:
=> Booting Thin
=> Rails 3.2.13 application starting in development on http://0.0.0.0:5000
=> Call with -d to detach
=> Ctrl-C to shutdown server
>> Thin web server (v1.5.1 codename Straight Razor)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:5000, CTRL+C to stop
Any idea why the server hangs when I try to instantiate the PubsubSubscriber class in the initializer? Is there a better place to start this up?
# example modified from https://github.com/redis/redis-rb/blob/master/examples/pubsub.rb
class PubsubSubscriber
def initialize
$redis.psubscribe( :channel_one ) do |on|
on.psubscribe do |event, total|
end
on.pmessage do |pattern, event, message|
# message received, kick off some workers
end
on.punsubscribe do |event, total|
end
end
end
end
One problem that you are having is that EventMachine is not ready yet when you are in the initializer. So wrapping your initialization in EM.next_tick
will delay your code until EventMachine is ready:
EM.next_tick { ... EventMachine code here ... }
When I tried this, my server started up all the way... and then blocked when the call to $redis.psubscribe fired.
However, switching to em-hiredis worked:
# config/initializers/redis_pubsub.rb
EM.next_tick do
$emredis = EM::Hiredis.connect(uri)
$emredis.pubsub.subscribe('channelone') do |message|
Rails.logger.debug message
end
end
This is occurring because the standard redis gem is not listening for events through the EventMachine interface - it is just creating a connection to your redis server and then blocking everything else.
In order to take advantage of EM you would need to set up a simple connection, in the form of:
class RedisConnection
# connect to redis
def connect(host, port)
EventMachine.connect host, port, self
end
def post_init
# send subscribe channel_one to redis
end
def receive_data(data)
# channel_one messages will arrive here
end
end
I've got a working example in this gist: https://gist.github.com/wheeyls/5647713
em-hiredis is a redis client that uses this interface.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With