propagate signals to running commands

otherwise, we have long running processes when GitLab terminates jobs in
a pipeline
This commit is contained in:
Martin Diehl 2022-03-06 21:09:46 +01:00
parent 425d148ea8
commit 445d5ec720
1 changed files with 22 additions and 7 deletions

View File

@ -6,9 +6,10 @@ import os
import subprocess import subprocess
import shlex import shlex
import re import re
import signal
import fractions import fractions
from collections import abc from collections import abc
from functools import reduce from functools import reduce, partial
from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any, Collection from typing import Callable, Union, Iterable, Sequence, Dict, List, Tuple, Literal, Any, Collection
from pathlib import Path from pathlib import Path
@ -174,21 +175,35 @@ def run(cmd: str,
Output of the executed command. Output of the executed command.
""" """
def pass_signal(sig,_,proc,default):
proc.send_signal(sig)
signal.signal(sig,default)
signal.raise_signal(sig)
signals = [signal.SIGINT,signal.SIGTERM]
print(f"running '{cmd}' in '{wd}'") print(f"running '{cmd}' in '{wd}'")
process = subprocess.run(shlex.split(cmd), process = subprocess.Popen(shlex.split(cmd),
stdout = subprocess.PIPE, stdout = subprocess.PIPE,
stderr = subprocess.PIPE, stderr = subprocess.PIPE,
env = os.environ if env is None else env, env = os.environ if env is None else env,
cwd = wd, cwd = wd,
encoding = 'utf-8', encoding = 'utf-8')
timeout = timeout) # ensure that process is terminated (https://stackoverflow.com/questions/22916783)
sig_states = [signal.signal(sig,partial(pass_signal,proc=process,default=signal.getsignal(sig))) for sig in signals]
try:
stdout,stderr = process.communicate(timeout=timeout)
finally:
for sig,state in zip(signals,sig_states):
signal.signal(sig,state)
if process.returncode != 0: if process.returncode != 0:
print(process.stdout) print(stdout)
print(process.stderr) print(stderr)
raise RuntimeError(f"'{cmd}' failed with returncode {process.returncode}") raise RuntimeError(f"'{cmd}' failed with returncode {process.returncode}")
return process.stdout, process.stderr return stdout, stderr
execute = run execute = run