Monday, January 24, 2011

Run a subprocess with a timeout

While tweaking a supybot IRC bot command for running Qalculate, I had the need to limit the execution time to guard from long-running expressions. From Stack Overflow I found this and modified it for my needs:

from subprocess import Popen, PIPE                                              
import signal
class ProcessTimeout(Exception):
    pass

def timeout_handler(signum, frame):
    raise ProcessTimeout

def run_timeout(cmd, timeout=None):
    if timeout:
        signal.signal(signal.SIGALRM, timeout_handler)
        signal.alarm(timeout)
    proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
    stdout = stderr = ''
    try:
        stdout, stderr = proc.communicate()
        signal.alarm(0)
    except ProcessTimeout:
        proc.kill()
        stdout = 'Calculation was taking too long, so I killed it dead.'
    del proc
    return (stdout, stderr)

Then, just call run_timeout with a list of command arguments and move on.