【问题标题】:How Elixir Supervisor stops children on stop?Elixir Supervisor 如何阻止孩子停下来?
【发布时间】:2017-06-15 03:53:34
【问题描述】:

我有一个主管 :simple_one_to_one 重启策略,当我调用 Supervisor.stop(sup) 时,孩子会发生什么?

从测试中我看到,无论他们在做什么,他们都会死去。是否有标准方法可以优雅地关闭它们,以便他们可以完成工作(如果有的话)?比如给他们打电话GenServer.stop...

【问题讨论】:

    标签: elixir erlang-supervisor


    【解决方案1】:

    伊万。我认为你想在你的工人身上设置出口。如果你不诱捕他们,他们只会被杀死。这是我的意思的说明:

    defmodule SupervisorStop do
      use Application
    
      def start(_type, _args) do
        import Supervisor.Spec, warn: false
    
        children = [ worker(SupervisorStop.Worker, []) ]
    
        opts = [strategy: :simple_one_for_one, name: SupervisorStop.Supervisor]
        Supervisor.start_link(children, opts)
      end
    end
    
    defmodule SupervisorStop.Worker do
      use GenServer
      require Logger
    
      def start_link(args) do
        GenServer.start_link(SupervisorStop.Worker, args, [])
      end
    
      def init(trap_exit) do
        Logger.info "#{inspect self} trap_exit: #{inspect trap_exit}"
        if trap_exit do
          Process.flag(:trap_exit, true)
        end
        {:ok, []}
      end
    
      def terminate(reason,_state) do
        Logger.info "terminating: #{inspect self}: #{inspect reason}"
        :ok
      end      
    end
    

    如果我在 iex 中运行它会发生什么:

    09:55:26 alex@alexmac test0 > iex -S mix
    Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
    
    Compiling 1 file (.ex)
    Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
    iex(1)> Supervisor.start_child(SupervisorStop.Supervisor, [true])
    
    09:59:16.086 [info]  #PID<0.102.0> trap_exit: true
    {:ok, #PID<0.102.0>}
    iex(2)> Supervisor.start_child(SupervisorStop.Supervisor, [false])
    {:ok, #PID<0.104.0>}
    
    09:59:21.113 [info]  #PID<0.104.0> trap_exit: false
    iex(3)> Supervisor.stop(SupervisorStop.Supervisor)
    
    09:59:35.702 [info]  terminating: #PID<0.102.0>: :shutdown
    :ok
    iex(4)>
    09:59:35.710 [info]  Application test0 exited: normal
    
    nil
    

    从输出中可以看出,被困退出的工人在死亡之前调用了它的终止回调

    09:59:16.086 [信息] #PID trap_exit: true ... 09:59:35.702 [info] 终止:#PID: :shutdown

    另一个 pid 没有报告它的终止调用。那是因为

    09:59:21.113 [info] #PID trap_exit: false

    如果你真的想了解所有不同的组合,这篇文章非常有用:

    http://crypt.codemancers.com/posts/2016-01-24-understanding-exit-signals-in-erlang-slash-elixir/

    【讨论】:

    • 好吧,我最终通过 Task.async 在主管的所有孩子上运行 GenServer.stop(child) 并在此之后停止主管。我的主要目标是让服务器完成他们正在做的任何事情,但阻止接收更多消息。你的实验证明,当主管停止时,孩子们会被残忍地杀害,正如我所怀疑的那样。谢谢!
    【解决方案2】:

    套用这篇伟大的文章:“谁监督主管”

    当顶级主管被要求终止时,它会在每个 Pid 上调用 exit(ChildPid, shutdown)。如果孩子是工人并且陷阱退出,它将调用自己的终止函数。否则,它只会死。当主管收到关闭信号时,它会以同样的方式将其转发给自己的孩子。

    简而言之,如果您想优雅地关闭工作人员:

    • 让它陷阱退出
    • 在其terminate 函数中处理关机

    来源:http://learnyousomeerlang.com/supervisors

    【讨论】:

      猜你喜欢
      • 2019-07-09
      • 2019-05-14
      • 1970-01-01
      • 2019-09-03
      • 1970-01-01
      • 2015-01-13
      • 1970-01-01
      • 1970-01-01
      • 2010-11-01
      相关资源
      最近更新 更多