正常关闭GenServer [英] Graceful shutdown of GenServer

查看:9
本文介绍了正常关闭GenServer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用GenServer编写了一个Elixir应用程序,它在引导时启动外部应用程序,并在退出时将其关闭并执行其他清理。我已在init/1回调中添加了启动功能,并在terminate/2回调中添加了清理代码。

启动GenServer时init代码运行正常,手动发送:stop信号时也会调用terminate方法,但在IEX中出现意外关机和中断(如按Ctrl+C)时,不会调用终止代码。


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

发件人Elixir Docs - GenServers

如果GenServer接收到退出信号(即不是:normal) 从任何进程中,当它没有捕获退出时,它将突然退出 原因相同,所以不调用terminate/2。请注意,一个 默认情况下,进程不会退出NOT陷阱,并发送退出信号 链接进程退出或其节点断开连接时。

因此,不能保证在执行以下操作时调用terminate/2 GenServer退出。出于这样的原因,我们通常推荐重要的 要在单独的进程中执行的清理规则,可以使用 或通过链接本身进行监视。

但我完全不知道如何使用:init.stoplinked 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

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

正如您注意到的,无法从内部捕获突然退出的BEAM OS进程。这是一个自定义属性:BEAM进程突然终止,因此它不能运行任何代码(因为它终止了)🙂。因此,如果BEAM被粗暴地终止,则不会调用回调。

如果您无条件地希望在BEAM终止时执行某些操作,则需要从另一个操作系统进程检测到这一点。我不确定您的确切用例是什么,但是假设您对此有一些强烈的需求,那么在同一台(或另一台)机器上运行另一个BEAM节点可以在这里工作。然后,您可以让一个节点上的一个进程监视另一个节点上的另一个进程,这样即使BEAM被粗暴地杀死,您也可以做出反应。

但是,如果您不需要无条件地运行某些清理逻辑,那么您的生活将会更简单,因此请考虑terminate中的代码是必需的,还是非常有用的。

这篇关于正常关闭GenServer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆