Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redis pub/sub on rails

Following the Redis Pub/Sub

this works fine and i can publish messages in any class using

$redis.publish 'channel', { object: @object.id }

using redis-cli > MONITOR, I can verify that this request was published correctly

[0 127.0.0.1:64192] "publish" "channel" "{:object=>\"5331d541f4eec77185000003\" }"

the problem starts when I add a subscriber block to that channel in other class (listener class) like the following

class OtherClass
  $redis.subscribe('channel') do |payload|
    p payload
  end
end

in redis-cli > MONITOR, shows also that the listener is subscribed correctly

[0 127.0.0.1:52930] "subscribe" "channel"

the problem is that when i add the subscriber listener class to the same rails app... it stop working cause the OtherClass listens to the redis server and halt the execution of any other code... it just sit there listening.

so is there a way to make a messaging bus with redis on the same rails app... so that events are published from some classes or service objects and there are listeners for specific channels to act upon receiving events in the background.

i know that i might use sidekiq or any other background worker to do this job... but after a while the background workers became messy and unmaintainable.

like image 212
a14m Avatar asked Mar 25 '14 19:03

a14m


People also ask

Is Redis good for Pubsub?

Aside from data storage, Redis can be used as a Publisher/Subscriber platform. In this pattern, publishers can issue messages to any number of subscribers on a channel. These messages are fire-and-forget, in that if a message is published and no subscribers exists, the message evaporates and cannot be recovered.

How do I use Redis as a pub sub?

Basic Pub-Sub modelStart by opening three terminal sessions and launch the Redis CLI in each of them. Once you have all the terminals open and set up, use one of the terminals to SUBSCRIBE to a channel. The name will entirely depend on you, and you can name it whatever you want.

Is Redis Pub/Sub blocking?

Redis' pub/sub sends messages to clients subscribed (listening) on a channel. If you are not listening, you will miss the message (hence the blocking call).

Is Redis Pub/Sub push or pull?

Pub/Sub is synchronous communication (push protocol). All parties need to be active at the same time to be able to communicate. Here Redis is a pure synchronous messaging broker.


1 Answers

The implementation of Redis#subscribe is a loop that will assume control of the current thread in order to listen to events. This means the boot process is halted when dropping a subscription into the context of a Rails class in the way you've shown.

You could try wrapping the call in a thread, but this approach would literally create a new subscription each time this class loaded in a new process, like a rails console or multiple unicorns. Plus, you'd have to be careful about shared state and other threading issues. This is probably not what you want.

You're best off starting a different process that loads the rails environment and subscribes to redis separately from the process(es) serving web requests. It could be a rake task like the following:

namespace :subscribe do
  task :redis => :environment do
    $redis.subscribe("bravo") do |on|
      on.message do |channel, message|
        Rails.logger.info("Broadcast on channel #{channel}: #{message}")
        OtherClass.some_method # yada yada
      end
    end
  end
end
like image 144
rossta Avatar answered Oct 22 '22 15:10

rossta