我使用 GenServer 编写了一个 Elixir 应用程序,该应用程序在启动时启动外部应用程序,然后将其关闭,并在退出时进行其他清理。我在中添加了启动功能init/1 https://hexdocs.pm/elixir/GenServer.html#c:init/1回调和清理代码在terminate/2 https://hexdocs.pm/elixir/GenServer.html#c:terminate/2打回来。
The init
当 GenServer 启动时,代码工作正常,并且terminate
方法也被调用时:stop
信号是手动发送的,但是如果 IEx 中出现意外关闭和中断(例如按 Ctrl+C),则不会调用终止代码。
目前,我已经浏览了大量的论坛主题、博客文章和文档,包括:
- 入门:基因服务器 http://elixir-lang.org/getting-started/mix-otp/genserver.html
- Elixir-Lang-Talk:退出 iex -S mix 时正常关闭 GenServer https://groups.google.com/forum/#!msg/elixir-lang-talk/d2z2lZnoa6w/0FX4tg0fCAAJ
- Elixir-Lang-Talk:停止 Genserver 与 Process.exit https://groups.google.com/forum/#!topic/elixir-lang-talk/vxOtIXdqiWw
From Elixir 文档 - GenServers https://hexdocs.pm/elixir/GenServer.html#c:terminate/2:
If the GenServer
收到退出信号(即不是:normal
)
任何进程在不捕获退出时都会突然退出
出于同样的原因,所以不打电话terminate/2
。请注意,一个
过程确实NOTtrap默认退出并发送退出信号
当链接的进程退出或其节点断开连接时。
因此不能保证terminate/2
当一个GenServer
退出。出于这些原因,我们通常建议重要的
清理规则发生在单独的进程中,或者通过使用
监控或通过链接本身。
但我完全不知道如何得到:init.stop
, linked processes
或其他任何与此相关的内容(因为这是我第一次使用 GenServers)。
这是我的代码:
defmodule MyAwesomeApp do
use GenServer
def start do
GenServer.start_link(__MODULE__, nil)
end
def init(state) do
# Do Bootup stuff
IO.puts "Starting: #{inspect(state)}"
{:ok, state}
end
def terminate(reason, state) do
# Do Shutdown Stuff
IO.puts "Going Down: #{inspect(state)}"
:normal
end
end
MyAwesomeApp.start
为了增加机会terminate
回调被调用时,服务器进程应该捕获退出。然而,即使如此,在某些情况下也可能不会调用回调(例如,当进程被残酷终止时,或者当进程自身崩溃时)。欲了解更多详情,请参阅here http://elixir-lang.org/docs/stable/elixir/GenServer.html#c:terminate/2.
如前所述,如果您想礼貌地关闭系统,您应该调用:init.stop
,这将递归地关闭监督树,导致terminate
要调用的回调。
正如您所注意到的,无法捕获 BEAM OS 进程从内部突然退出。这是一个自定义属性:BEAM 进程突然终止,因此它无法运行任何代码(因为它终止了)????。因此,如果 BEAM 被粗暴终止,回调将不会被调用。
如果您无条件地想要在 BEAM 终止时执行某些操作,则需要从另一个操作系统进程中检测到这一点。我不确定您的确切用例是什么,但假设您对此有一些强烈的需求,那么在同一台(或另一台)机器上运行另一个 BEAM 节点可以在这里工作。然后,您可以让一个节点上的一个进程监视另一节点上的另一个进程,这样即使 BEAM 被残酷杀死,您也可以做出反应。
但是,如果您不需要无条件运行一些清理逻辑,您的生活会更简单,因此请考虑中的代码是否terminate
是必须的,或者更确切地说,是锦上添花的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)