From ca5be9d848c002017a5b8de70ccd1c7bea7a69d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20T=C3=B3th?= Date: Sun, 12 May 2019 22:30:49 +0200 Subject: [PATCH] Detect errors in the subprocess of CommandEventHandler --- lib/tfw/components/pipe_io_event_handler.py | 33 +++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/lib/tfw/components/pipe_io_event_handler.py b/lib/tfw/components/pipe_io_event_handler.py index d60fedf..676a8e5 100644 --- a/lib/tfw/components/pipe_io_event_handler.py +++ b/lib/tfw/components/pipe_io_event_handler.py @@ -6,11 +6,14 @@ from os import getpgid, killpg from os.path import join from signal import SIGTERM from secrets import token_urlsafe +from time import sleep +from threading import Thread +from contextlib import suppress from tfw import EventHandlerBase from tfw.config.logs import logging -from .pipe_io_server import PipeIOServer +from .pipe_io_server import PipeIOServer, terminate_process_on_failure LOG = logging.getLogger(__name__) DEFAULT_PERMISSIONS = 0o600 @@ -107,18 +110,36 @@ class CommandEventHandler(PipeIOEventHandler): self._proc_stdout = open(self.pipe_io.in_pipe, 'wb') self._proc = Popen( command, shell=True, executable='/bin/bash', - stdin=self._proc_stdin, stdout=self._proc_stdout, + stdin=self._proc_stdin, stdout=self._proc_stdout, stderr=PIPE, start_new_session=True ) + self._poll_check_proc_thread = self._start_poll_check_proc() def _generate_tempfilename(self): # pylint: disable=no-self-use random_filename = partial(token_urlsafe, 10) return join('/tmp', f'{type(self).__name__}.{random_filename()}') + def _start_poll_check_proc(self): + thread = Thread(target=self._poll_check_proc, daemon=True) + thread.start() + return thread + + @terminate_process_on_failure + def _poll_check_proc(self): + while True: + self.check_proc() + sleep(1) + + def check_proc(self): + if self._proc.poll() is not None: + _, stderr = self._proc.communicate() + raise RuntimeError(f'Subprocess failed: {stderr.decode()}') + def cleanup(self): - process_group_id = getpgid(self._proc.pid) - killpg(process_group_id, SIGTERM) - self._proc_stdin.close() - self._proc_stdout.close() + with suppress(ProcessLookupError): + process_group_id = getpgid(self._proc.pid) + killpg(process_group_id, SIGTERM) + self._proc_stdin.close() + self._proc_stdout.close() super().cleanup()