Rails 5, начальная нить из инициализатора сошла с ума

У меня есть следующий код в config/application.rb:

config.after_initialize do
  MyConcern.init_processing
end

Тогда следующие родственные методы:

def init_processing
  @queue_processor = Thread.new do
    process_op_queue
  end
  @queue_processor.name = "Some Queue"
  # @queue_processor_notifier = Queue.new
end

def process_op_queue
  while true
    req = MyRequest.where(done: Helper::FALSE_NIL_OR_MISSING, started_at: nil).order_by(id: :asc).find_one_and_update({'$currentDate' => {started_at: true}}, return_document: :after)
    req ? process_queue_item(req) : sleep(30)
  end
end

По сути, запуск потока при запуске сервера для выполнения некоторых фоновых задач, принимаемых приложением от пользователей по HTTP-вызовам.

В режиме разработки все работает нормально. Запуск в производственной среде с тем же сервером Puma, @queue_processor показывает мертвых (с рельсов консоли):

MyConcern.instance_variable_get("@queue_processor").join
=> #<Thread:0x00000002b8fa68@MyConcern Queue@/var/lib/openshift/5842d71a5110e25cdf00000c/app-root/runtime/repo/app/controllers/concerns/my_concern.rb:23 dead> 
MyConcern.instance_variable_get("@queue_processor").value
=> false

Во-первых, для меня (мягко сказано) неочевидно, как поток может умереть без исключения и вернуть false с циклом, который я описал выше в process_op_queue, Другие очень интересные факты:

  1. на самом деле есть поток, выполняющий работу, очевидную для меня, когда он выполняет запросы к приложению и просматривает изменения в базе данных.
  2. в консоли рельсов вижу только одну ветку:

,

2.3.1 :009 > Thread.list
 => [#<Thread:0x000000012f63a8 run>] 
2.3.1 :010 > 

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

1 ответ

Читая о пуме и работниках, мне неясно, что за магия делает пума, когда она разветвляет рабочих и т. Д. Итак, в итоге мы решили создать для нее грабли:

rails g task mynamespace process_queue

Затем положить в lib/tasks/mynamespace.rake код, необходимый для запуска процессора:

namespace :mynamespace do
  desc "Process reuqest queue"
  task process_queue: :environment do
    MyConcern.process_op_queue
  end
end

Затем запустите это как отдельный процесс вместо отдельного потока приложения. Это позволяет запускать столько процессоров и столько контейнеров, сколько мне нравится. Хорошая вещь с задачей rake состоит в том, что она имеет все поведение как в самом приложении. Это означает MyModel.something будет автоматически работать как внутри приложения.

nohup bin/rails mynamespace:process_queue > my.log
Другие вопросы по тегам