处理gen_server状态的清理

Ric*_*rdo 7 erlang 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Ada*_*erg 11

terminate/2在内部发生崩溃时调用,gen_server即使它没有捕获出口,如果它从链接到它的某个其他进程收到"退出",也不会被调用,如果你需要清理那么它应该捕获出口(使用process_flag(trap_exit, true)).

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

我会考虑三种选择:

  1. 当下一个进程实例启动时处理左侧文件(例如,in init/1)
  2. 陷阱退出,清理文件,然后再次崩溃,原因相同
  3. 有一个第三个进程监视gen_server其唯一目的是清理文件

选项1可能是最好的选择,因为至少代码不会捕获退出并且您可以免费获得持久状态.由于上述原因,选项2不太好,它可以隐藏和掩盖其他错误.3是混乱的,因为在gen_server再次启动之前可能无法完成清理过程.

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