示例#1
0
async def run_task(context, to_cancellable_process):
    """Run the task, sending stdout+stderr to files.

    https://github.com/python/asyncio/blob/master/examples/subprocess_shell.py

    Args:
        context (scriptworker.context.Context): the scriptworker context.
        to_cancellable_process (types.Callable): tracks the process so that it can be stopped if the worker is shut down

    Returns:
        int: 1 on failure, 0 on success

    """
    env = deepcopy(os.environ)
    env["TASK_ID"] = context.task_id or "None"
    kwargs = {
        "stdout": PIPE,
        "stderr": PIPE,
        "stdin": None,
        "close_fds": True,
        "preexec_fn": lambda: os.setsid(),
        "env": env
    }  # pragma: no branch

    subprocess = await asyncio.create_subprocess_exec(
        *context.config["task_script"], **kwargs)
    context.proc = await to_cancellable_process(TaskProcess(subprocess))
    timeout = context.config["task_max_timeout"]

    with get_log_filehandle(context) as log_filehandle:
        stderr_future = asyncio.ensure_future(
            pipe_to_log(context.proc.process.stderr,
                        filehandles=[log_filehandle]))
        stdout_future = asyncio.ensure_future(
            pipe_to_log(context.proc.process.stdout,
                        filehandles=[log_filehandle]))
        try:
            _, pending = await asyncio.wait([stderr_future, stdout_future],
                                            timeout=timeout)
            if pending:
                message = "Exceeded task_max_timeout of {} seconds".format(
                    timeout)
                log.warning(message)
                await context.proc.stop()
                raise ScriptWorkerTaskException(
                    message,
                    exit_code=context.config["task_max_timeout_status"])
        finally:
            # in the case of a timeout, this will be -15.
            # this code is in the finally: block so we still get the final
            # log lines.
            exitcode = await context.proc.process.wait()
            # make sure we haven't lost any of the logs
            await asyncio.wait([stdout_future, stderr_future])
            # add an exit code line at the end of the log
            status_line = "exit code: {}".format(exitcode)
            if exitcode < 0:
                status_line = "Automation Error: python exited with signal {}".format(
                    exitcode)
            log.info(status_line)
            print(status_line, file=log_filehandle)
            stopped_due_to_worker_shutdown = context.proc.stopped_due_to_worker_shutdown
            context.proc = None

    if stopped_due_to_worker_shutdown:
        raise WorkerShutdownDuringTask

    return 1 if exitcode != 0 else 0
示例#2
0
async def test_stop_handle_process_lookup_error():
    process = MagicMock()
    process.terminate.side_effect = ProcessLookupError
    task_process = TaskProcess(process)
    await task_process.stop()
示例#3
0
async def test_set_killed_due_to_worker_shutdown():
    task_process = TaskProcess(MagicMock())
    assert task_process.stopped_due_to_worker_shutdown is False
    await task_process.worker_shutdown_stop()
    assert task_process.stopped_due_to_worker_shutdown is True