2017-05-06 76 views
1

我有一個班我想確保正確關閉。特別是,即使我的主進程從外部事件中死亡(例如:SIGTERM),我也希望它關閉。如何保證正確關閉

如果'異常'死亡,上下文管理器和atexit將不會被調用。所以我一直在嘗試使用信號來捕獲事件,然後運行我特定的清理代碼。

但現在我正在進入python清理不同類型的出口的雜草。例如,雖然我可以捕獲signal.SIGTERM並添加我自己的處理程序,但我不知道如何在完成時調用默認處理程序。但不是專家,我不喜歡讓我的圖書館用我自己的代碼接管適當的系統退出。

(具體細節:我使用的是擱置,如果你不關閉一個架子,將保持在鎖定和未打開的狀態 - 基本無法使用。)

上午我做這個太辛苦?我會認爲確保我可以妥善清理不應該需要深厚的專業知識。如果我真的需要捕獲信號然後接管系統退出,我可以簡單地執行我的清理代碼,並且如果唯一的其他處理程序是SIG_DFL,那麼我只是做一個sys.exit()?這聽起來很危險,但那樣可以嗎?

我當前的代碼:

def reg_sig(signum): 
    old_handler = signal.getsignal(signum) 

    def sighandler(signum, frame): 
     close_open_objects() # <== my custom code 
     if callable(old_handler): 
      old_handler() 
     else: 
      # What goes here? 
      # do_default_handler() # <- this seems ideal 
      # or 
      # sys.exit() 

    try: 
     # I'm not sure what signals might be called so I register a bunch. 
     signal.signal(signum, sighandler) 
    except Exception as err: 
     pass 

# Register signals 
for sig in [signal.SIGHUP, signal.SIGINT, signal.SIGQUIT, signal.SIGABRT, 
      signal.SIGKILL,signal.SIGTERM]: 
    reg_sig(sig) 
+1

請注意,SIGKILL(和SIGSTOP)不能被接收信號的進程捕獲。還有更多的「外部事件」無法捕捉 - 例如,從計算機中拉動電源。你在編寫什麼惡劣環境需要你嘗試捕捉所有信號? –

+0

可能的重複:https://stackoverflow.com/questions/23468042/the-invocation-of-signal-handler-and-atexit-handler-in-python#23468485 –

+0

@MathiasRav - OP說這是一個問題與'擱置'數據庫。 – tdelaney

回答

3

一個簡單的解決方案是使用的atexit和註冊調用sys.exit(0)信號處理程序。請注意,這會改變流程退出代碼與通常在信號情況下返回的代碼。 From a related answer

import sys, atexit, signal 
atexit.register(close_open_objects) # Your custom code 
signal.signal(signal.SIGTERM, lambda n, f: sys.exit(0)) 
+0

問題 - 這個退出本質上等於正常的SIGTERM(或其他)關閉嗎?我擔心的是,通過接管SIGTERM或其他信號,我將以一種我不明白的方式改變python的退出行爲。如果一個SIGTERM應該總是打印一個堆棧跟蹤,或者註冊一個事件,或者寫回家給媽媽呢?我有點擔心奪取殺人賽事的所有權。 –

+0

如果希望庫組件能夠以不干擾同一進程中的其他組件的方式處理信號,則需要添加一個工具來協調不同的信號處理程序。 Python標準庫中沒有這種東西,所以您需要在應用程序中安裝單個信號處理程序,並且可能允許組件以某種方式掛接到信號處理程序。一些組件**必須**擁有kill事件的所有權 - 最好是專用於信號處理的組件。 –

+0

好的 - 這正是我所掌握的。只是要確認 - 沒有辦法捕獲信號,做我的事情,然後重新將它提升回python的默認信號處理程序,對吧? –