Как заставить Bluepill перезапускать Resque worker только после достижения безопасного статуса

Допустим, это мой рабочий:

class FooWorker
  @queue = :foo

  def self.perform
    User.all.each do |u|
      ...
      Do Long Operations (Unsafe to kill)
      ...

      # Here it's safe to break the worker and restart
    end
  end
end

Я проверяю это с помощью Resque Scheduler, и это моя конфигурация Bluepill:

...
app.process(process_name) do |process|
  process.group         = "resque"
  process.start_command = "rake environment resque:work QUEUE=foo RAILS_ENV=production"
  ...
  process.stop_signals  = [:quit, 5.seconds, :term, 1.minute, :kill]
  process.daemonize     = true

  process.start_grace_time = 30.seconds
  process.stop_grace_time  = 80.seconds

  process.monitor_children do |child_process|
    child_process.stop_command = "kill -QUIT {{PID}}"

    child_process.checks :mem_usage, :every => 30.seconds, :below => 500.megabytes, :times => [3,4], :fires => :stop
  end
end
....

Я хотел бы заставить Bluepill или Resque ждать, пока он не достигнет "безопасного" блока, для перезапуска или выключения. Как этого добиться?


person CodeOverload    schedule 24.08.2013    source источник
comment
Могут ли ваши длительные операции быть помещены в транзакцию базы данных, чтобы в случае их прерывания система оставалась в чистом состоянии? Не тот ответ, который вы ищете, но, возможно, это альтернативный подход?   -  person Graham Savage    schedule 20.09.2013
comment
Вы нашли какое-нибудь решение?   -  person Robert    schedule 05.08.2014


Ответы (1)


Попробуйте так:

1) Установите resque для изящного убийства детей в TERM / INT с помощью _ 1_, задав переменные TERM_CHILD и RESQUE_TERM_TIMEOUT env при запуске:

process.start_command = "rake environment resque:work QUEUE=foo RAILS_ENV=production TERM_CHILD=1 RESQUE_TERM_TIMEOUT=20.0"

Значение по умолчанию для RESQUE_TERM_TIMEOUT - 4 секунды .

Это заставит resque отправить сигнал TERM дочернему элементу, дождаться RESQUE_TERM_TIMEOUT и, если дочерний элемент все еще запущен, убить его. Обязательно

а) установите этот тайм-аут достаточно большим, чтобы критическая секция закончилась,

б) настройте тайм-аут Bluepill TERM в process.stop_signals, чтобы он был немного больше, чем RESQUE_TERM_TIMEOUT, чтобы не убивать воркера, пока он ожидает, пока дочерний процесс завершит критическую секцию.

2) Обработайте сигнал TERM в дочернем процессе, чтобы корректно остановиться:

class FooWorker
  class << self
    attr_accessor :stop
  end

  @queue = :foo
  def self.perform
    User.all.each do |u|
      ...
      Do Long Operations (Unsafe to kill)
      ...

      # Here it's safe to break the worker and restart
      return if FooWorker.stop
    end
  end
end

trap('TERM') do
  FooWorker.stop = true
end
person biomancer    schedule 22.09.2013