Detect errors in the subprocess of CommandEventHandler

This commit is contained in:
Kristóf Tóth 2019-05-12 22:30:49 +02:00
parent 78d70f2f8b
commit ca5be9d848

View File

@ -6,11 +6,14 @@ from os import getpgid, killpg
from os.path import join from os.path import join
from signal import SIGTERM from signal import SIGTERM
from secrets import token_urlsafe from secrets import token_urlsafe
from time import sleep
from threading import Thread
from contextlib import suppress
from tfw import EventHandlerBase from tfw import EventHandlerBase
from tfw.config.logs import logging 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__) LOG = logging.getLogger(__name__)
DEFAULT_PERMISSIONS = 0o600 DEFAULT_PERMISSIONS = 0o600
@ -107,18 +110,36 @@ class CommandEventHandler(PipeIOEventHandler):
self._proc_stdout = open(self.pipe_io.in_pipe, 'wb') self._proc_stdout = open(self.pipe_io.in_pipe, 'wb')
self._proc = Popen( self._proc = Popen(
command, shell=True, executable='/bin/bash', 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 start_new_session=True
) )
self._poll_check_proc_thread = self._start_poll_check_proc()
def _generate_tempfilename(self): def _generate_tempfilename(self):
# pylint: disable=no-self-use # pylint: disable=no-self-use
random_filename = partial(token_urlsafe, 10) random_filename = partial(token_urlsafe, 10)
return join('/tmp', f'{type(self).__name__}.{random_filename()}') 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): def cleanup(self):
process_group_id = getpgid(self._proc.pid) with suppress(ProcessLookupError):
killpg(process_group_id, SIGTERM) process_group_id = getpgid(self._proc.pid)
self._proc_stdin.close() killpg(process_group_id, SIGTERM)
self._proc_stdout.close() self._proc_stdin.close()
self._proc_stdout.close()
super().cleanup() super().cleanup()