Michael
Michael

Reputation: 13914

Function Timeout API for Python

I am trying to implement a function that will timeout if it fails to complete in a certain amount of time (having issues with a thread hanging). This answer seemed the most promising, effectively providing an API wrapper with which to call my actual function. It generally seems to work (see loop_forever), but fails to stop when I use time.sleep. Why does the timeout not work with the sleep timer and will this work as a way to prevent threads from hanging?

import signal
import time

def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None):


    class TimeoutError(Exception):
        pass

    def handler(signum, frame):
        raise TimeoutError()

    # set the timeout handler
    signal.signal(signal.SIGALRM, handler) 
    signal.alarm(timeout_duration)
    try:
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
    finally:
        signal.alarm(0)

    return result




def loop_forever():
    x = 0
    while True:
        print x
        try:
            x += 1
        except:
            continue

def loop_forever_sleep():
    x = 0
    while True:
        print x
        try:
            x += 1
            time.sleep(10)
        except:
            continue

if __name__ == '__main__':
    a = timeout(loop_forever) #Terminates
    b = timeout(loop_forever_sleep) #Does not terminate

Upvotes: 1

Views: 124

Answers (1)

dano
dano

Reputation: 94871

The problem is that the SIGALRM is being raised while you're inside of the time.sleep(10) system call, which causes your handler to be called in that context, too. However, you're swallowing all the exceptions that happen inside of your infinite loop, so the TimeoutError never makes it back to the timeout function, instead it gets ignored by the except: continue code inside of loop_forever_sleep. Just remove the try/except block from the while True loop and it will work fine:

def loop_forever_sleep():
    x = 0
    while True:
        print x
        x += 1
        time.sleep(10)

Upvotes: 1

Related Questions