Source code for gigl.src.common.utils.timeout

import errno
import os
import signal
from functools import wraps

from gigl.common.logger import Logger

[docs] logger = Logger()
[docs] class TimedOutException(Exception): pass
[docs] def timeout( seconds=10, error_message=os.strerror(errno.ETIME), timeout_action_func=None, exception_thrown_on_timeout=TimedOutException, **timeout_action_func_params, ): """ Decorator to exit a program when a function execution exceeds a specified timeout. This decorator exits the program when the decorated function timed out, and executes timeout_action_func before exiting. The timeout_action_func can be useful for cases like environment clean up (e.g., ray.shutdown()). Another way to handle timeouts, especially when there are multiple threads or child threads, is to run `func` with multiprocessing. However, multiprocessing does not work with Ray. References to the current timeout implementation: - https://docs.python.org/3/library/signal.html - https://www.saltycrane.com/blog/2010/04/using-python-timeout-decorator-uploading-s3/ Parameters: - seconds (int): Timeout duration in seconds. Defaults to 10. - error_message (str): Error message to log on timeout. Defaults to os.strerror(errno.ETIME). - timeout_action_func (callable, optional): Function to execute before exiting on timeout. - exception_thrown_on_timeout (Exception): Exception to raise on timeout. Defaults to TimedOutException. - **timeout_action_func_params: Arbitrary keyword arguments passed to timeout_action_func. """ def decorator(func): def _handler(signum, frame): logger.info(error_message) if timeout_action_func: timeout_action_func(**timeout_action_func_params) raise exception_thrown_on_timeout() def wrapper(*args, **kwargs): old = signal.signal(signal.SIGALRM, _handler) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: # cancel the alarm signal.alarm(0) # reinstall the old signal handler signal.signal(signal.SIGALRM, old) return result return wraps(func)(wrapper) return decorator