当工人退出时,在主管中执行操作

时间:2016-02-08 12:19:31

标签: elixir

工作人员退出后是否有办法在主管中执行操作(除了重新启动工作人员外)。

目前我在工作人员(下方)中有一些代码似乎运行了大约一半的时间。

try do 
   some_work()

catch :exit, reason
   save_reason_to_db()
   exit(reason)

这名工人有一个单一的障碍,只有一名工人在跑步。所以每次工人退出主管都会开始一个新的。

似乎这个工作者每次第二次退出,它运行save_reason_to_db(),并且每隔一次运行它。

3 个答案:

答案 0 :(得分:4)

我不是OTP专家,但最简单的解决办法可能就是在主管中设置第二个流程来监控失败的流程并完成工作(比如将理由保存到db或发出一些通知) )。

这种关注在应用程序结构(主管)和对流程生命周期事件的反应之间很好地分开。

答案 1 :(得分:4)

你可以做一些清理或者你需要做的任何事情 terminate / 2回调函数,它是genserver行为的一部分。

请参阅here并阅读更多here too

因此,在Supervisor工作者规范中,确保关闭选项设置为:brutal_kill。如果设置为:brutal_kill,则不会运行genserver worker中的terminate / 2回调。阅读more here。您应该将关闭选项设置为适合您的应用程序的超时,例如:shutdown: 10_000

在你的genserver中,在init/1 call中,将trap exits标志设置为true:

:erlang.process_flag(:trap_exit, :true)

或使用纯灵药

Process.flag(:trap_exit, :true)

然后你可以在你的genserver worker声明一个终止回调函数:

  def terminate(reason, state) do
    save_reason_to_db()
    :ok
  end

答案 2 :(得分:1)

这不是我自己的问题的答案,但我发现了导致我遇到问题的错误。

问题是工人实际上是rabbitmq的消费者,而catch块中的一个动作是 ack 拒绝使用rabbitmq消息。

然后,rabbitmq立即向工作人员发出下一条消息,然后工作人员立即调用exit(reason)并在没有实际尝试执行消息的情况下死亡。

我的解决方案是删除退出(原因)行,并更紧密地匹配原因,因为没有理由让工人死亡。

try do 
  some_work()

catch :exit, :timeout
  save_reason_to_db()

感谢您的投入 - 很高兴有选择:)