0

我一直在 Heroku 上使用 resque,它会不时用 SIGTERM 中断你的工作。

到目前为止,我已经用一个简单的方法处理了这个问题:

def process(options)
  do_the_job
rescue Resque::TermException
  self.defer options
end

我们已经开始使用 resque-status 以便我们可以跟踪作业,但是上面的方法显然打破了这一点,因为当作业实际上被推迟到另一个作业时,它会显示已完成。

我目前的想法是,与其在 resque 中推迟当前的工作,还需要另一个工作来重新排队由于 SIGTERM 而失败的工作。

诀窍在于一些工作更复杂:

def process(options)
  do_part1 unless options['part1_finished']
  options['part1_finished']
  do_part2
rescue Resque::TermException
  self.defer options
end

当 do_part1 重复时,简单地删除救援并简单地重试这些作业会导致异常。

4

1 回答 1

0

更深入地研究 resque-status 的工作原理,一种可能的解决方法是使用 resque-status 将使用的相同参数直接进入 resque 重新队列。

def process
  do_part1 unless options['part1_finished']
  options['part1_finished']
  do_part2
rescue Resque::TermException
  Resque.enqueue self.class, uuid, options
  raise DeferredToNewJob
end

当然,这是未记录的,因此可能与未来版本的 resque-status 不兼容。

有一个缺点:在该作业失败和新作业捡起它之间,第一个作业的状态将由 resque-status 报告。这就是我重新提出一个新异常的原因 - 否则工作状态将显示为已完成,直到新工作人员接手旧工作,这可能会混淆正在观察和等待工作完成的进程。

通过引发一个新的异常 DeferredToNewJob,作业状态会暂时显示失败,这在前端更容易解决,并且可以从 resque 失败队列中自动清除特定的异常。

更新

resque-status 为处理程序提供支持on_failure。如果将具有此名称的方法定义为类上的实例方法,我们可以使这更简单

这是我的 on_failure

def on_failure(e)
  if e.is_a? DeferredToNewJob
    tick('Waiting for new job')
  else
    raise e
  end
end

有了这个,作业基本上不会花时间处于失败状态的进程来监视它的状态。此外,如果 resque-status 找到了这个处理程序,那么它不会将异常提升到 resque,因此它不会被添加到失败的队列中。

于 2017-02-02T15:46:40.557 回答