Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to kick off pubsub subscriber in Rails app

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
like image 303
99miles Avatar asked May 22 '13 20:05

99miles


1 Answers

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.

like image 183
Wheeyls Avatar answered Sep 28 '22 05:09

Wheeyls