|  | 
| 17 | 17 | 
 | 
| 18 | 18 | import asyncio | 
| 19 | 19 | from asyncio.subprocess import PIPE | 
|  | 20 | +from contextlib import contextmanager | 
| 20 | 21 | import os | 
| 21 | 22 | import re | 
|  | 23 | +import signal | 
| 22 | 24 | import subprocess | 
| 23 | 25 | import sys | 
| 24 | 26 | 
 | 
|  | 
| 36 | 38 | _DEFAULT_BUF_SIZE = 1024 * 64 | 
| 37 | 39 | 
 | 
| 38 | 40 | 
 | 
|  | 41 | +@contextmanager | 
|  | 42 | +def capture_signal(signalnum, callback): | 
|  | 43 | +    """ | 
|  | 44 | +    Install handler to capture signal | 
|  | 45 | +
 | 
|  | 46 | +    Args: | 
|  | 47 | +        signalnum: signal to capture | 
|  | 48 | +        callback: callback if signal occurs | 
|  | 49 | +
 | 
|  | 50 | +    """ | 
|  | 51 | +    original_handler = signal.getsignal(signalnum) | 
|  | 52 | +    signal.signal(signalnum, callback) | 
|  | 53 | +    try: | 
|  | 54 | +        yield | 
|  | 55 | +    finally: | 
|  | 56 | +        signal.signal(signalnum, original_handler) | 
|  | 57 | + | 
|  | 58 | + | 
| 39 | 59 | async def watch(stream, proc_per_host): | 
| 40 | 60 |     """Process the stdout and stderr streams on the fly. | 
| 41 | 61 |     Decode the output lines | 
| @@ -118,9 +138,10 @@ async def run_async(cmd, processes_per_host, env, cwd, stderr, **kwargs): | 
| 118 | 138 |         cmd, env=env, cwd=cwd, stdout=PIPE, stderr=stderr, **kwargs | 
| 119 | 139 |     ) | 
| 120 | 140 | 
 | 
| 121 |  | -    output = await asyncio.gather( | 
| 122 |  | -        watch(proc.stdout, processes_per_host), watch(proc.stderr, processes_per_host) | 
| 123 |  | -    ) | 
|  | 141 | +    with capture_signal(signal.SIGTERM, lambda signalnum, *_: proc.send_signal(signalnum)): | 
|  | 142 | +        output = await asyncio.gather( | 
|  | 143 | +            watch(proc.stdout, processes_per_host), watch(proc.stderr, processes_per_host) | 
|  | 144 | +        ) | 
| 124 | 145 |     return_code = proc.returncode | 
| 125 | 146 |     return return_code, output, proc | 
| 126 | 147 | 
 | 
| @@ -198,7 +219,8 @@ def check_error(cmd, error_class, processes_per_host, cwd=None, capture_error=Tr | 
| 198 | 219 |         process = subprocess.Popen( | 
| 199 | 220 |             cmd, env=os.environ, cwd=cwd or environment.code_dir, stderr=stderr, **kwargs | 
| 200 | 221 |         ) | 
| 201 |  | -        return_code = process.wait() | 
|  | 222 | +        with capture_signal(signal.SIGTERM, lambda signalnum, *_: process.send_signal(signalnum)): | 
|  | 223 | +            return_code = process.wait() | 
| 202 | 224 |     if return_code: | 
| 203 | 225 |         extra_info = None | 
| 204 | 226 |         if return_code == 137: | 
|  | 
0 commit comments