Skip to content

Instantly share code, notes, and snippets.

@ChuckFoo
Created September 3, 2015 18:26
Show Gist options
  • Select an option

  • Save ChuckFoo/dd5f4edd8c236d19f721 to your computer and use it in GitHub Desktop.

Select an option

Save ChuckFoo/dd5f4edd8c236d19f721 to your computer and use it in GitHub Desktop.
isolate yourself from crashy binary modules in Python using multiprocessing
###########################################################################
#
# 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