0

If I run 'make' command in subprocess.Popen it doesn't terminate after timeout

    with subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process:
    try:
        stdout, stderr = process.communicate(input, timeout=timeout)
    except subprocess.TimeoutExpired:
        process.kill()
        stdout, stderr = process.communicate()

I tried will

subprocess.check_output and subprocess.run

and they also don't work.

If a run each command from Makefile independently using the method above, it works fine.

  • why are you passing some input if you don't redirect input? – Jean-François Fabre Aug 02 '21 at 20:33
  • @Jean-FrançoisFabre the input doesn't matter in my case. And yes, it can be removed. The issue is that the 'make' command doesn't terminate. Inside Makefile there is a program launch with an infinity loop and if I run it this way instead of 'make' it was killed successfully – Ilya Zlatkin Aug 03 '21 at 00:58

2 Answers2

0

When using subprocess I often try to do pursue the easiest path to get the desired result. Having said that, I would recommend just adding a timeout to your script being called and eliminate any need to try and kill it.

For example:

timeout_length = 30 # seconds
command = "make"
subprocess.Popen(['timeout', timeout_length, command], 
                 stdout=subprocess.PIPE, 
                 stderr=subprocess.PIPE)
Teejay Bruno
  • 1,716
  • 1
  • 4
  • 11
  • Thank you, it works fine on Linux, but there is no timeout on MacOS. There is an alternative, but it makes the program platform dependant and/or require extra tools to install – Ilya Zlatkin Aug 03 '21 at 01:12
  • `subprocess.run` and friends hae a `timeout` keyword argument; use that intead of bare `Popen` maybe. The `Popen` documentation specifically recommends that you should avoid it and prefer the higher-level `subprocess` functions whenever you can. – tripleee Aug 03 '21 at 08:37
0

one classical issue is that

process.kill()

doesn't kill child processes. Maybe in your case, a child process is running and isn't stopped, specially if the main makefile calls other makefiles.

In that case, apply the recipe found in an answer to how to kill process and child processes from python?

import psutil

with subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as process:
try:
    stdout, stderr = process.communicate(input, timeout=timeout)
except subprocess.TimeoutExpired:
    # create a parent psutil process object
    parent = psutil.Process(process.pid)
    # list all child processes and kill them
    for child in parent.children(recursive=True):  # or parent.children() for recursive=False
       child.kill()
    # kill parent process as done earlier
    process.kill()
    stdout, stderr = process.communicate()
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219