【问题标题】:How to run Elixir Supervisor in escript如何在 escript 中运行 Elixir Supervisor
【发布时间】:2015-01-13 20:15:45
【问题描述】:

我有一个混合项目,其中包含尽可能简单的 Supervisor 和 GenServer。当我从 iex 打电话时:

EchoCmd.Supervisor.start_link([:Hello])
GenServer.call(:echoserver, :echo)
GenServer.call(:echoserver, :mumble)
GenServer.call(:echoserver, :echo)

:mumble 调用引发异常,然后 GenServer 重新启动,第二个 :echo 调用正常。

如果我以任何其他方式运行代码,Supervisor 将无法重新启动 GenServer。例如,我用主模块创建项目的 escript 如下:

defmodule EchoCmd.Echo do
    def main(args) do
        EchoCmd.Supervisor.start_link([:Hello])
        GenServer.call(:echoserver, :echo)
        GenServer.call(:echoserver, :mumble)
        GenServer.call(:echoserver, :echo)
    end
end

:mumble 调用引发异常,并且 escript 终止,而 Supervisor 没有重新启动 GenServer。

我没有包含 Supervisor 和 Server 模块代码,因为从 iex 调用它们时它们工作正常,所以我猜这里不需要它们。

我有概念上的误解吗?这是不可能的,还是我做错了什么?

【问题讨论】:

    标签: erlang-otp elixir erlang-supervisor gen-server elixir-mix


    【解决方案1】:

    Escript 的行为是正确的。您只是想念 iex shell 如何“帮助您”。

    您在代码中所做的是启动一个链接进程,而不是让它崩溃。并且由于它是一个链接进程,当它出现故障时,它应该会关闭所有链接进程。可能会有一些“例外”,但您的 escript 进程正在发生什么。

    shell 和进程管理器都可以处理“我死了,你也应该这样”的消息。他们通过改变进程(链接进程,而不是垂死的进程)处理此类消息的方式来做到这一点。它允许他们将它们作为普通消息接收(如果您愿意,您可以在receive 子句中接收)而不是特殊的内部消息。为了改变这种行为,他们使用Process.flag( :trap_exit, :true)elixir doc 指向eralng's one)。它允许 shell 只打印被杀死进程的死亡,而不是每次你做坏事时死亡。

    所以你可以做同样的事情。更改此标志,如果您不想在此类消息上的 receive 中进行模式匹配。但我认为这不是你要找的。由于您的进程是单例的,并且主管会重新启动,因此您实际上没有任何理由首先链接到它。不需要更新死亡和重启,让主管担心。就像乔·阿姆斯特朗(Joe Armstrong)所说(可能是意译)

    您无需知道如何修理自动售货机即可使用它。

    所以,start,而不是start_link

    也就是说,您可能会考虑创建与主管的链接,这也可能在重启太多次后死掉(他可能被告知以这种方式行事)。它允许你在你死时带走他(和监督的过程)。或者,他可以与您的主管、申请主管或以其他方式联系起来。这取决于您的域,并且没有错误的决定,您只需要检查什么对您有用。这是设计决策,您必须进行试验或阅读更多相关信息:

    http://elixir-lang.org/getting_started/mix_otp/5.html

    http://www.erlang.org/doc/design_principles/des_princ.html

    http://learnyousomeerlang.com/supervisors

    【讨论】:

      【解决方案2】:

      问题不在于您的服务器和主管,而在于您调用它们的方式。如果服务器退出而另一个进程正在等待对GenServer.call 的回复,则调用进程也会退出,因此最后一次调用永远不会发生。原因是如果同步调用失败(GenServer.call 是同步的,而不是GenServer.cast),进程不可能在无效状态下继续。如果您这样做只是为了测试主管,那么您可以尝试:

      defmodule EchoCmd.Echo do
          def main(args) do
              EchoCmd.Supervisor.start_link([:Hello])
              GenServer.cast(:echoserver, :echo)
              GenServer.cast(:echoserver, :mumble)
              GenServer.cast(:echoserver, :echo)
          end
      end
      

      它在iex 中起作用的原因是iex 捕获了出口并允许您输入另一行。

      【讨论】:

      • 好吧,经过多次笨手笨脚和牦牛剃须,这是我的问题,以及不足的 :timer.sleeps。我可以使用在所有内容之后添加它们的 noobie 模式。如果我使用 GenServer.start,我的 escript 从 :mumble 崩溃,但如果我使用 GenServer.start_link,它会报告错误并继续重新启动 GenServer。我知道它应该反过来工作,但我会阅读。谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-23
      • 2020-03-20
      • 2017-06-15
      • 1970-01-01
      • 2012-09-01
      • 2019-07-09
      • 1970-01-01
      相关资源
      最近更新 更多