我有一个可能因异常而终止的python服务-我可以接受。但是问题在于它催生了一个子进程,即使其父进程失败了,该子进程仍继续运行。
import multiprocessing as mp
from time import sleep
import os
import atexit
import psutil
@atexit.register # Doesn't fired at exception
def goodbye():
current_process = psutil.Process()
children = current_process.children(recursive=True)
for child in children:
print('Kill child with pid {}'.format(child.pid))
try:
child.terminate()
except:
pass
print("You are now leaving the Python sector.")
def func(): # Child process
while True:
ppid = os.getppid()
print("Parent process id:", ppid)
if ppid == 1:
print("Parent process has terminated")
break
sleep(1)
t = mp.Process(target=func, args=())
t.start()
print(9 + "0") # Exception here
print("I'm ok")
服务将继续(正式)运行,直到获得外界的认可:
Parent process id: 29118
Traceback (most recent call last):
File "stestcp.py", line 32, in <module>
print(9 + "0") # Exception here
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Parent process id: 29118
Parent process id: 29118
Parent process id: 29118
Parent process id: 29118
Parent process id: 29118
^CError in atexit._run_exitfuncs:
Traceback (most recent call last):
File "/usr/lib/python3.6/multiprocessing/popen_fork.py", line 28, in poll
Process Process-1:
pid, sts = os.waitpid(self.pid, flag)
KeyboardInterrupt
Traceback (most recent call last):
File "/usr/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
self.run()
File "/usr/lib/python3.6/multiprocessing/process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "stestcp.py", line 27, in func
sleep(1)
KeyboardInterrupt
Kill child with pid 29119
You are now leaving the Python sector.
问题是-当程序因异常而失败时,是否有任何方法可以调用某些全局回退函数(例如atexit)?
答案 0 :(得分:0)
感谢Andrej Kesely,找到了解决方案。现在的工作示例如下:
import multiprocessing as mp
from time import sleep
import sys
import os
import atexit
import psutil
class ExitHooks(object):
def __init__(self):
self.exit_code = None
self.exception = None
def hook(self):
self._orig_exit = sys.exit
sys.exit = self.exit
sys.excepthook = self.exc_handler
def exit(self, code=0):
self.exit_code = code
self._orig_exit(code)
def exc_handler(self, exc_type, exc, *args): # Called at exception
self.exception = exc
goodbye()
hooks = ExitHooks()
hooks.hook()
@atexit.register # Doesn't fired at exception
def goodbye():
if hooks.exit_code is not None:
print("death by sys.exit(%d)" % hooks.exit_code)
elif hooks.exception is not None:
print("death by exception: %s" % hooks.exception)
else:
print("natural death")
current_process = psutil.Process()
children = current_process.children(recursive=True)
for child in children:
print('Kill child with pid {}'.format(child.pid))
try:
child.terminate()
except:
pass
print("You are now leaving the Python sector.")
def func(): # Child process
while True:
ppid = os.getppid()
print("Parent process id:", ppid)
if ppid == 1:
print("Parent process has terminated")
break
sleep(1)
t = mp.Process(target=func, args=())
t.start()
sleep(2)
print(9 + "0") # Exception here