Watch at Ease看見世界,讀懂生活。

技术 · 實用指南

Python subprocess 逾時但子程序仍運行?先稽核程序群組與管線

選擇 terminate、群組訊號或遞迴清理前,追蹤直接子程序、後代、session、process group 與繼承的 pipe writer。

Original diagram mapping a Python parent, direct child, descendants and inherited pipe writer
原創示意圖:發訊號前先標示程序、群組與管線 ownership。 Watch at Ease

逾時只證明一次等待超過期限,不能證明工作只有一個 PID、後代仍在同一群組,或 stdout、stderr 已沒有其他寫端。

安全作法是替啟動加上 token,記錄拓撲與管線狀態,再使用真正擁有工作的最窄平台機制;寬限後才升級,並用真實 launcher 驗證退出與關閉。

清理前凍結逾時證據

記錄 launch token、父與直接子 PID、PPID chain、命令、開始時間、session、PGID,以及 shell 與 capture 設定;leader 退出前完成。

分開記錄 leader 是否存活、剩餘後代與 communicate 是否等待 open pipe。直接子程序死亡但 reader 阻塞是 pipe ownership 問題。

選擇 ownership unit

單一程序可只依直接子程序合同;會啟動 shell、worker 或 build tool 時,需界定 POSIX group、遞迴 descendants、Windows job 或直接 child。

不要向未核驗 PID 推導的 group 發訊號。啟動時記錄 leader 與成員,排除無關服務;setsid 逃逸需要其他 supervisor。

只控制自己建立的 POSIX group

整棵樹屬於本次請求時,可用 start_new_session=True。逾時先向已核驗 group 發溫和訊號,有限等待後再升級並 reap 直接 child。

多執行緒程式避免盲用 preexec_fn,改用文件參數;再次檢查成員,因 descendants 可能另建 session。

將繼承 pipe 當成獨立 gate

所有 writer 關閉後 capture pipe 才會結束。shell、worker pool 或 helper 可在 child 已死後仍持有 stdout 或 stderr。

保留 TimeoutExpired 部分輸出,處理已證實的 writer,再 drain pipe;不要以丟棄輸出掩蓋 hang。

依平台分支並驗證

沒有適合 group 時,可用 psutil 及早快照遞迴 descendants,terminate、wait 再 kill survivors 並核對 identity。

透過真實 launcher 重播:證明 child 與 descendants 消失、pipe 按時關閉、輸出按設計保留、exit 已 reap,且 sentinel 仍存活。

Original decision diagram for leader reaping, descendant exit, pipe closure and collateral safety
原創示意圖:四個獨立逾時驗收 gate 全部通過才算完成。 Watch at Ease