async def _get_proc_output(
    proc: asyncio.subprocess.Process,
    in_data: Optional[bytes],
    timeout: Optional[int],
    text: Union[bool, FormatType],
) -> Tuple[ProcessData, ProcessData, Optional[int]]:
    stdout: Any
    stderr: Any
    try:
        stdout, stderr = await asyncio.wait_for(proc.communicate(in_data),
                                                timeout)
    except asyncio.TimeoutError:
        try:
            proc.kill()
        except ProcessLookupError:
            pass

        raise

    if text:
        if text is not StderrOnly and stdout is not None:
            stdout = stdout.decode(errors="replace").strip()

        if stderr is not None:
            stderr = stderr.decode(errors="replace").strip()

    return stdout, stderr, proc.returncode
Exemple #2
0
async def terminate_and_wait(proc: asyncio.subprocess.Process) -> None:
    try:
        proc.terminate()
        try:
            await asyncio.wait_for(proc.wait(), timeout=2.0)
        except asyncio.TimeoutError:
            proc.kill()
            await proc.wait()
    except ProcessLookupError:
        pass
Exemple #3
0
async def _get_proc_output(proc: asyncio.subprocess.Process,
                           input: Optional[bytes],
                           timeout: int) -> Tuple[bytes, bytes, Optional[int]]:
    try:
        stdout, stderr = await asyncio.wait_for(proc.communicate(input),
                                                timeout)
    except asyncio.TimeoutError:
        try:
            proc.kill()
        except ProcessLookupError:
            pass

        raise
    return stdout, stderr, proc.returncode
Exemple #4
0
async def _terminate_process(process: asyncio.subprocess.Process, timeout: int,
                             logger: logging.Logger) -> None:
    returncode = process.returncode
    if returncode is not None:
        logger.info(f"Process has exited with {returncode}")
        return
    logger.info(f"Stopping process with SIGTERM, waiting {timeout} seconds")
    process.terminate()
    try:
        returncode = await asyncio.wait_for(process.wait(), timeout=timeout)
        logger.info(f"Process has exited after SIGTERM with {returncode}")
    except TimeoutError:
        logger.info(
            f"Process hasn't exited after {timeout} seconds, SIGKILL'ing...")
        process.kill()
Exemple #5
0
async def close_subprocess(
        # TODO[Pylint issue 1469]: Does not recognize `asyncio.subprocess`.
        subprocess: asyncio.subprocess.Process,  # pylint: disable=no-member
) -> None:
    """Ensure the given subprocess is terminated."""
    # We do not know what state the process is in.
    # We assume the user had already exhausted
    # all nice ways to terminate it.
    # So just kill it.
    with contextlib.suppress(ProcessLookupError):
        subprocess.kill()
    # Killing just sends the request / signal.
    # Wait to make sure it is actually terminated.
    # And automatically-created pipes and inherited fds,
    # such as any given in stdin, stdout, stderr,
    # are closed after termination.
    await subprocess.communicate()
async def soft_kill(process: asyncio.subprocess.Process) -> None:
    # First try terminating...
    try:
        process.terminate()
        await asyncio.wait_for(process.wait(), timeout=45.0)
        return
    except ProcessLookupError:
        # (can be thrown e.g. if the process has exited in the meantime)
        return
    except asyncio.TimeoutError:
        pass

    # ... then try killing
    try:
        process.kill()
        await process.wait()
    except ProcessLookupError:
        return
Exemple #7
0
async def _terminate_process(process: asyncio.subprocess.Process,
                             logger: logging.Logger,
                             timeout: int = 30) -> None:
    logger.info(
        f"Stopping process {process} with SIGINT, waiting {timeout} seconds")
    if process.returncode is not None:
        logger.info(f"Process is already terminated with {process.returncode} "
                    "perhaps it died prematurely")
        return
    process.send_signal(signal.SIGINT)
    try:
        await asyncio.wait_for(process.wait(), timeout=timeout)
        logger.info(f"Stopped process {process} with SIGINT")
    except TimeoutError:
        logger.info(
            f"Process {process} didn't close after {timeout} seconds, killing..."
        )
    finally:
        if process.returncode is None:
            process.kill()
Exemple #8
0
async def kill_process(
        proc: asyncio.subprocess.Process, wait: float,
        logger: logging.Logger) -> None:  # pylint: disable=no-member
    if proc.returncode is None:
        try:
            proc.terminate()
            await asyncio.sleep(wait)
            if proc.returncode is None:
                try:
                    proc.kill()
                except Exception:
                    if proc.returncode is not None:
                        raise
            await proc.wait()
            logger.info("Process killed: pid=%d; retcode=%d", proc.pid,
                        proc.returncode)
        except asyncio.CancelledError:
            pass
        except Exception:
            if proc.returncode is None:
                logger.exception("Can't kill process pid=%d", proc.pid)
            else:
                logger.info("Process killed: pid=%d; retcode=%d", proc.pid,
                            proc.returncode)
Exemple #9
0
 async def kill_process(self, proc: asyncio.subprocess.Process):
     proc.terminate()
     try:
         await asyncio.wait_for(proc.wait(), timeout=20)
     except TimeoutError:
         proc.kill()