处理gen_server状态的清理

时间:2011-02-25 15:31:39

标签: erlang otp

我有一个gen_server正在运行,它必须在正常停止或意外崩溃时清理其状态。清理主要包括删除一些文件。

此时,当gen_server崩溃或正常停止时,清理工作在terminate/2完成。

如果terminate/2崩溃,有没有理由不调用gen_server

如果gen_server意外死亡,应监控gen_server等待清理的任何其他进程吗?

所以,代码是这样的:

terminate(normal, State) ->
    % Invoked when the process stops
    % Clean up the mess
terminate(Error, State) ->
    % Invoked when the process crashes
    % Clean up the mess

编辑:我在官方邮件列表中发现了这封电子邮件,它正在谈论同样的事情:

http://groups.google.com/group/erlang-programming/browse_thread/thread/9a1ba2d974775ce8

正如亚当在下面所说,如果我们想避免陷入gen_server中的存在,我们可以使用不同的方法。

但是如果我们捕获存在,terminate/2似乎是一个安全的地方进行清理,因为它总是被调用。此外,我们必须在'EXIT'发送到terminate/2handle_call/3时正确处理,并尝试在工人和主管之间正确传播错误。

2 个答案:

答案 0 :(得分:11)

terminate/2内发生崩溃时会调用

gen_server,即使它没有捕获退出,如果它从链接到它的某个其他进程收到'EXIT',它也不会被调用,如果你需要清理它,它应该捕获退出(使用process_flag(trap_exit, true))。

这种行为有点不幸,因为它很难为gen_server进程编写可靠的关闭过程。此外,仅仅为了能够运行terminate/2来捕获出口并不是一个好习惯,因为您可能会捕获许多其他错误,这使得调试系统变得更加困难。

我会考虑三种选择:

  1. 当下一个流程实例开始时处理左侧文件(例如,在init/1中)
  2. 陷阱退出,清理文件,然后因同样的原因再次崩溃
  3. 有第3个进程监视gen_server,其唯一目的是清理文件
  4. 选项1可能是最好的选择,因为至少代码不会捕获退出并且您可以免费获得持久状态。由于上述原因,选项2不太好,它可以隐藏和掩盖其他错误。 3是混乱的,因为在gen_server再次启动之前可能无法完成清理过程。

    仔细考虑你要清理的原因,以及在进程崩溃时是否真的必须完成(毕竟这是一个bug)。要小心,你最终不要做太多的防御性编程。

答案 1 :(得分:0)

这是非常新鲜和相关的 When does terminate/2 get called in a gen_server?