2

subprocess timeout=SECONDS don't work for me if I follow the advice of the python docs:

# copy+pasteable snippet :-)
import subprocess32 as subprocess
import datetime

now=datetime.datetime.now()
pipe=subprocess.Popen('sleep 5', shell=True, stdout=subprocess.PIPE)
try:
    pipe.communicate(timeout=1)
except subprocess.TimeoutExpired, exc:
    time_delta=datetime.datetime.now()-now
    print(time_delta)
    assert time_delta<datetime.timedelta(seconds=3), time_delta
    pipe.kill()
    outs, errs = pipe.communicate()
    time_delta=datetime.datetime.now()-now
    print(time_delta)
    assert time_delta<datetime.timedelta(seconds=3), time_delta
    print('OK')

The docs advice to use pipe.kill() and pipe.communicate() after TimeoutExpired: https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate

It does not work for me. The second communicate() does not return soon.

Exception:

0:00:01.001234
0:00:05.002919
Traceback (most recent call last):
  File "/home/foo/src/test_timeout.py", line 16, in <module>
    assert time_delta<datetime.timedelta(seconds=3), time_delta
AssertionError: 0:00:05.002919

If I use ['sleep', '5'] instead of shell=True, then it works. If I don't supply stdout=subprocess.PIPE, then it works, too.

I guess the shell does not react on the pipe.kill().

What is the best way to solve this?

guettli
  • 25,042
  • 81
  • 346
  • 663

1 Answers1

1

The general pattern: catch TimeoutExpired, kill started processes, call .communicate() again is correct.

The issue is that pipe.kill() in your code kills only the shell while its descendant processes such as /bin/sleep may continue to run. See How to terminate a python subprocess launched with shell=True.

Note: if desired; it is not necessary to wait for grandchildren processes. See Python subprocess .check_call vs .check_output.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670