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.
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