2011-02-25 57 views
7

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

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

如果gen_server崩溃,terminate/2不会被调用吗?

如果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

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

但是,如果我们陷入存在,terminate/2似乎是一个安全的地方做清理,因为它总是会被称为。此外,我们必须正确处理'EXIT'发送到terminate/2handle_call/3试图在工作人员和主管之间正确传播错误。

回答

11

terminate/2gen_server内部发生崩溃时被调用,即使它不捕获退出,如果它从链接到它的某个其他进程接收到“退出”,它将不会被调用,以防您需要清理那么它应该陷入退出(使用process_flag(trap_exit, true))。

此行为有点不幸,因为它使gen_server过程难以编写可靠的关闭过程。此外,为了能够运行terminate/2而陷入退出并不是一个好习惯,因为您可能会遇到很多其他错误,这些错误会使系统更难调试。

我会考虑三个选项:

  1. 处理的遗留文件的过程的下一个实例启动时(例如,在init/1
  2. 陷阱退出,清理文件,然后崩溃再次用同样的理由
  3. 有一个第三过程,监控其唯一目的是清理文件

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

仔细想想为什么要清理,以及是否真的必须在进程崩溃时完成(毕竟它是一个错误)。小心你不要做太多的防守编程。

+0

亚当,为什么作为CW发布? – 2011-02-25 15:52:09

+0

如果我错了,请纠正我,但即使'gen_server'没有陷入退出,AFAIK' terminate/2'也会被调用。当你的父母崩溃时,需要处理他们。 – Ricardo 2011-02-25 16:05:27

+0

我运行了一些测试,'gen_server'崩溃时调用'terminate/2',所以在什么情况下可能不会调用'terminate/2'? – Ricardo 2011-02-25 16:21:01