Redis pub/sub на рельсах

Следуя Redis Pub/Sub

это прекрасно работает, и я могу публиковать сообщения в любом классе, используя

$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"

проблема в том, что когда я добавляю класс слушателя-слушателя к тому же рельсовому приложению... он перестает работать, потому что OtherClass слушает сервер redis и останавливает выполнение любого другого кода... он просто сидит там слушать.

так есть способ сделать шину обмена сообщениями с redis на одном и том же приложении rails... так что события публикуются из некоторых классов или служебных объектов, и есть слушатели для определенных каналов, чтобы воздействовать на получение событий в фона.

Я знаю, что я мог бы использовать sidekiq или любого другого фонового работника для выполнения этой работы... но через некоторое время фоновые работники стали беспорядочными и недостижимыми.

Ответ 1

Реализация Redis#subscribe цикл, который будет контролировать текущий поток, чтобы прослушивать события. Это означает, что процесс загрузки останавливается при отбрасывании подписки в контексте класса Rails так, как вы показали.

Вы можете попробовать обернуть вызов в потоке, но этот подход будет буквально создавать новую подписку каждый раз, когда этот класс загружается в новый процесс, например, консоль рельсов или несколько единорогов. Кроме того, вы должны быть осторожны в отношении общих состояний и других проблем с потоками. Вероятно, это не то, что вы хотите.

Лучше всего начать другой процесс, который загружает среду рельсов и подписывается на redis отдельно от процесса (ов), обслуживающего веб-запросы. Это может быть такая задача, как:

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