2011-02-25 105 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