簡體   English   中英

避免在殺死父進程時殺死孩子

[英]Avoid killing children when parent process is killed

我在基於燒瓶的Web應用程序使用庫多處理程序來啟動長時間運行的進程。 實現該功能的函數如下:

def execute(self, process_id):
    self.__process_id = process_id
    process_dir = self.__dependencies["process_dir"]
    self.fit_dependencies()
    process = Process(target=self.function_wrapper, name=process_id, args=(self.__parameters, self.__config, process_dir,))
    process.start()

當我想部署在此Web應用程序的一些代碼,我重新啟動重新啟動gunicorn服務,nginx的服務。 我的問題是,此重新啟動會終止此應用程序啟動的所有子進程,就像SIGINT信號已發送給所有子進程一樣。 我該如何避免呢?

編輯:閱讀此文章后 ,看來此行為是正常的。 答案建議改為使用子流程庫。 所以我重新提出我的問題:如果我想在python腳本中啟動長期運行的任務(即python函數),並確保它們能夠在父進程中幸存, 或者確保父進程(這是gunicorn實例),該如何處理)會在部署中生存嗎?

最終編輯:我選擇@noxdafox答案,因為它是更完整的答案。 首先,使用流程排隊系統可能是此處的最佳實踐。 然后,作為一種解決方法,我仍然可以使用多重處理,但是可以在函數包裝器中使用python-daemon上下文(請參見此處 ans here )。 最后,@ Rippr建議將子流程與不同的流程組一起使用,這比進行多處理的分叉要干凈,但是涉及要啟動的獨立功能(在我的情況下,我從導入的庫中啟動特定的功能)。

我建議您反對設計,因為它很容易出錯。 更好的解決方案將使用某種排隊系統( RabbitMQCeleryRedis等)將工作人員與服務器分離。

不過,您可以嘗試一些“技巧”。

  1. 將您的子進程轉換為UNIX守護程序。 python守護程序模塊可能是一個起點。
  2. 指示您的子進程忽略SIGINT信號。 如果子進程拒絕死亡,那么服務協調器可能會通過發出SIGTERMSIGKILL信號來解決此問題。 您可能需要禁用此功能。

    為此,只需在function_wrapper函數的開頭添加以下行:

     signal.signal(signal.SIGINT, signal.SIG_IGN) 

最終,這個問題歸結為對部署的含義的誤解。 在諸如Python之類的非企業語言(與諸如Erlang之類的企業語言相比)中,通常可以理解,部署消除了運行該過程的任何先前技術。 因此,如果您的舊子級/功能在執行新部署后實際上並未終止,那顯然是一個錯誤。

要扮演魔鬼的擁護者,即使從您的問題/規格中甚至不清楚您對部署的實際期望是什么—您只是希望舊的“功能”可以永遠運行? 這些功能首先如何開始? 誰應該知道這些“功能”是否在給定的部署中進行了修改,以及是否應該以什么方式重新啟動? 在Erlang / OTP(與Python無關)中對這些問題做了很多考慮,因此,當您使用甚至沒有設計的Python之類的語言時,您不能簡單地期望機器讀懂您的想法對於這樣的用例。

這樣,將長期運行的邏輯與其余代碼分開,並適當地執行部署可能是一個更好的選擇。 正如其他答案提到的那樣,這可能涉及直接從Python內部生成單獨的UNIX daemon ,甚至可能使用完全獨立的邏輯來處理這種情況。

除了@noxdafox的出色答案 ,我認為您可以考慮以下替代方案:

subprocess.Popen(['nohup', 'my_child_process'], preexec_fn=os.setpgrp)

基本上,子進程被殺死,因為它們與父進程屬於同一進程組。 通過添加preexec_fn=os.setpgrp參數,您只是在請求子進程在其自己的進程組中生成,這意味着它們將不會接收終止信號。

說明取自此處

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM