如何在复杂作业中使用resque-status处理SIGTERM

时间:2017-02-01 23:39:38

标签: heroku resque resque-status

我一直在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重复时导致异常。

1 个答案:

答案 0 :(得分:0)

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

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,因此它不会被添加到失败的队列中。