这很好用,我可以使用
在任何类中发布消息$redis.publish 'channel', { object: @object.id }
使用redis-cli > MONITOR
,我可以验证此请求是否已正确发布
[0 127.0.0.1:64192] "publish" "channel" "{:object=>\"5331d541f4eec77185000003\" }"
当我在其他类(监听器类)中将订阅者阻止添加到该频道时,问题就会出现,如下所示
class OtherClass
$redis.subscribe('channel') do |payload|
p payload
end
end
redis-cli > MONITOR
中的也表明侦听器已正确订阅
[0 127.0.0.1:52930] "subscribe" "channel"
问题是,当我将订阅者监听器类添加到相同的rails应用程序时......它停止工作,因为OtherClass
监听redis服务器并停止执行任何其他代码...它只是坐在那里听。
有没有办法在同一个rails应用程序上使用redis创建消息传递总线...这样就可以从某些类或服务对象发布事件,并且有特定通道的侦听器在接收事件时采取行动背景。
我知道我可能会使用sidekiq或任何其他背景工作者来完成这项工作......但是一段时间后,后台工作人员变得混乱且无法维护。
答案 0 :(得分:14)
Redis#subscribe
的实现是a loop,它将控制当前线程以便侦听事件。这意味着在以您显示的方式将订阅放入Rails类的上下文时,将停止引导过程。
你可以尝试在一个线程中包装调用,但是每次在新进程中加载这个类时,这种方法都会创建一个新的订阅,比如rails控制台或多个独角兽。另外,您必须小心共享状态和其他线程问题。这可能不是你想要的。
您最好开始一个加载rails环境的不同进程,并与提供Web请求的进程分开订阅redis。它可能是一个像下面这样的rake任务:
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