Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python subprocess timeout?

Is there any argument or options to setup a timeout for Python's subprocess.Popen method?

Something like this:

subprocess.Popen(['..'], ..., timeout=20) ?

like image 987
sultan Avatar asked Sep 17 '10 07:09

sultan


People also ask

Does subprocess run wait?

subprocess. run() is synchronous which means that the system will wait till it finishes before moving on to the next command.

What is subprocess Popen in Python?

The subprocess module defines one class, Popen and a few wrapper functions that use that class. The constructor for Popen takes arguments to set up the new process so the parent can communicate with it via pipes. It provides all of the functionality of the other modules and functions it replaces, and more.

What is subprocess Check_output in Python?

The subprocess. check_output() is used to get the output of the calling program in python. It has 5 arguments; args, stdin, stderr, shell, universal_newlines. The args argument holds the commands that are to be passed as a string.


2 Answers

I would advise taking a look at the Timer class in the threading module. I used it to implement a timeout for a Popen.

First, create a callback:

def timeout( p ):
    if p.poll() is None:
        print 'Error: process taking too long to complete--terminating'
        p.kill()

Then open the process:

proc = Popen( ... )

Then create a timer that will call the callback, passing the process to it.

t = threading.Timer( 10.0, timeout, [proc] )
t.start()
t.join()

Somewhere later in the program, you may want to add the line:

t.cancel()

Otherwise, the python program will keep running until the timer has finished running.

EDIT: I was advised that there is a race condition that the subprocess p may terminate between the p.poll() and p.kill() calls. I believe the following code can fix that:

import errno

def timeout( p ):
    if p.poll() is None:
        try:
            p.kill()
            print 'Error: process taking too long to complete--terminating'
        except OSError as e:
            if e.errno != errno.ESRCH:
                raise

Though you may want to clean the exception handling to specifically handle just the particular exception that occurs when the subprocess has already terminated normally.

like image 109
dvntehn00bz Avatar answered Oct 23 '22 13:10

dvntehn00bz


subprocess.Popen doesn't block so you can do something like this:

import time

p = subprocess.Popen(['...'])
time.sleep(20)
if p.poll() is None:
  p.kill()
  print 'timed out'
else:
  print p.communicate()

It has a drawback in that you must always wait at least 20 seconds for it to finish.

like image 30
Abhishek Amit Avatar answered Oct 23 '22 13:10

Abhishek Amit