2

I have a python service which may be ended by exception - I'm ok with it. But the problem is that it spawned an child process which continues to run even it's parent got a fail.

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") 

And service continues to work (formally) until it got a kick from outside:

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. 

The question is - is there any way to call some global fallback function (like atexit) when program failed with exception?

1

1 Answer 1

1

Thanks to Andrej Kesely, solution found. Working example now looks like:

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 
Sign up to request clarification or add additional context in comments.

1 Comment

exception should be printed with traceback.print_exception(hooks.exception)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.