Created
September 3, 2015 18:26
-
-
Save ChuckFoo/dd5f4edd8c236d19f721 to your computer and use it in GitHub Desktop.
isolate yourself from crashy binary modules in Python using multiprocessing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ########################################################################### | |
| # | |
| # timeout wrapper around multiprocessing from: | |
| # http://code.activestate.com/recipes/577853-timeout-decorator-with-multiprocessing/ | |
| # modified to add crash detection without simply locking up or exitting completely | |
| # | |
| ########################################################################### | |
| class TimeoutException(Exception): | |
| pass | |
| class CrashException(Exception): | |
| pass | |
| class RunableProcessing(multiprocessing.Process): | |
| def __init__(self, func, *args, **kwargs): | |
| self.queue = multiprocessing.Queue(maxsize=1) | |
| args = (func,) + args | |
| multiprocessing.Process.__init__(self, target=self.run_func, args=args, kwargs=kwargs) | |
| def run_func(self, func, *args, **kwargs): | |
| try: | |
| result = func(*args, **kwargs) | |
| self.queue.put((True, result)) | |
| except Exception as e: | |
| self.queue.put((False, e)) | |
| def done(self): | |
| return self.queue.full() | |
| def result(self): | |
| return self.queue.get() | |
| # this decorator only works on functions that return something (could probably make that an option too) | |
| def TimeoutWithCrashIsolation(seconds, force_kill=True, detect_crash=True): | |
| def wrapper(function): | |
| def inner(*args, **kwargs): | |
| now = time.time() | |
| proc = RunableProcessing(function, *args, **kwargs) | |
| proc.start() | |
| proc.join(seconds) | |
| if proc.is_alive(): | |
| if force_kill: | |
| proc.terminate() | |
| runtime = int(time.time() - now) | |
| raise TimeoutException('fn "{0}" timed out after {1} seconds'.format(function.__name__,runtime)) | |
| if detect_crash and proc.exitcode < 0: | |
| raise CrashException('fn "{0}" crashed with exit code {1}'.format(function.__name__,proc.exitcode)) | |
| #assert proc.done() | |
| if not proc.done(): | |
| raise TimeoutException('fn "{0}" process is not done'.format(function.__name__)) | |
| success, result = proc.result() | |
| if success: | |
| return result | |
| else: | |
| raise result | |
| return inner | |
| return wrapper | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment