Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir GenServer的正常关闭_Elixir_Gen Server - Fatal编程技术网

Elixir GenServer的正常关闭

Elixir GenServer的正常关闭,elixir,gen-server,Elixir,Gen Server,我正在用GenServer编写一个Elixir应用程序,它在引导时启动一个外部应用程序,然后关闭它,并在退出时进行其他清理。我在回调中添加了启动功能,在回调中添加了清理代码 当GenServer启动时,init代码工作正常,当手动发送:stop信号时,terminate方法也被调用,但在IEx中出现意外关机和中断(如按下Ctrl+C)的情况下,不会调用终止代码。 目前,我浏览了大量论坛帖子、博客帖子和文档,包括: 发件人: 如果GenServer接收到退出信号(这不是:normal)

我正在用GenServer编写一个Elixir应用程序,它在引导时启动一个外部应用程序,然后关闭它,并在退出时进行其他清理。我在回调中添加了启动功能,在回调中添加了清理代码

当GenServer启动时,
init
代码工作正常,当手动发送
:stop
信号时,
terminate
方法也被调用,但在IEx中出现意外关机和中断(如按下Ctrl+C)的情况下,不会调用终止代码。


目前,我浏览了大量论坛帖子、博客帖子和文档,包括:

发件人:

如果
GenServer
接收到退出信号(这不是
:normal
) 在任何进程中,当它没有捕获退出时,它将突然退出 出于同样的原因,因此不要调用
终止/2
。请注意 默认情况下,进程不会捕获退出,并发送退出信号 当链接进程退出或其节点断开连接时

因此,不能保证在调用时调用
terminate/2
GenServer
退出。出于这些原因,我们通常建议 在单独的流程中通过使用 通过链接本身进行监控

但是我完全不知道如何使用
:init.stop
链接进程
或其他任何东西(因为这是我第一次使用GenServer)


这是我的代码:

defmodule MyAwesomeApp do
使用GenServer
def启动do
GenServer.start\u链接(\u模块\u,无)
结束
def初始(状态)do
#做一些启动的事情
IO.puts“开始:{inspect(state)}”
{:好的,州政府}
结束
def终止(原因、状态)do
#做关闭的事情
IO.puts“正在下降:{inspect(state)}”
:正常
结束
结束
MyAwesomeApp.start

我可以向您推荐两种解决方案

第一个在文档中提到

请注意,进程不会捕获出口

您必须使gen server进程陷阱退出。为此:

Process.flag(:trap_exit, true)
这会使您的进程调用在退出时终止/2


但另一个解决方案是将此初始化交给上级主管。然后让主管将外部应用程序引用传递给gen server。但在这里,如果需要退出外部应用程序,您没有类似于终止的回调。当监控程序停止时,外部应用程序将被终止。

要增加调用
终止
回调的机会,服务器进程应陷阱退出。但是,即使这样,在某些情况下(例如,当进程被残忍地杀死时,或者当它自己崩溃时),也可能不会调用回调。有关更多详细信息,请参阅

如前所述,如果您想礼貌地关闭系统,您应该调用
:init.stop
,这将递归地关闭监控树,从而导致调用
终止
回调


正如你们所注意到的,并没有办法从内部捕捉到突然的光束。这是一个自定义属性:如果您试图让BEAM进程在iex和进程中工作,BEAM进程将突然终止,因此它无法运行任何代码(因为它已终止),确保您使用的是
GenServer.start
而不是
GenServer.start\u link
,否则shell进程将崩溃,陷阱将无关紧要

下面是一个例子:

defmodule Server do

    use GenServer
    require Logger

    def start() do
      GenServer.start(__MODULE__, [], [])
    end


    def init(_) do
      Logger.info "starting"
      Process.flag(:trap_exit, true) # your trap_exit call should be here
      {:ok, :some_state}
    end

    # handle the trapped exit call
    def handle_info({:EXIT, _from, reason}, state) do
      Logger.info "exiting"
      cleanup(reason, state)
      {:stop, reason, state} # see GenServer docs for other return types
    end

    # handle termination
    def terminate(reason, state) do
      Logger.info "terminating"
      cleanup(reason, state)
      state
    end

    defp cleanup(_reason, _state) do
      # Cleanup whatever you need cleaned up
    end

end
在iex中,您现在应该看到一个被困的退出呼叫

iex> {:ok, pid} = Server.start()
iex> Process.exit(pid, :something_bad)

Process.flag(:trap\u exit,true)
对我不起作用。您能告诉我在genserver中应该在哪里调用它吗?您应该在过程中设置它,这意味着
init/1
似乎问题不在于gen server本身。启动一个
iex
shell,
Process.flag(:trap\u exit,true)
并编写一个简单的
receive
来匹配全部,似乎也不起作用。如果您的问题仅仅是关闭外部应用程序,那么当gen server自动停止时就会完成,但是关于您提到的其他清理,可能会更详细地告诉您将要做什么。>正如您所注意到的,无法从内部捕获操作系统进程退出。自从OTP 20+:处理信息({:退出,与终止/2有什么区别?