diff --git a/CHANGES.rst b/CHANGES.rst index 7b3b516..e1882d8 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,7 @@ 2.2.3 (unreleased) ------------------ -- Nothing changed yet. +- Much better handling of LibreOffice crashing or failing to start. 2.2.2 (2024-09-18) diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index b66f5ad..7913b68 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -11,3 +11,4 @@ Contributors * Socheat Sok, https://github.com/socheatsok78 * BohwaZ, https://github.com/bohwaz * ReeceJones, https://github.com/ReeceJones +* Grunthos, https://github.com/Grunthos diff --git a/src/unoserver/converter.py b/src/unoserver/converter.py index fd70802..144630e 100644 --- a/src/unoserver/converter.py +++ b/src/unoserver/converter.py @@ -68,7 +68,7 @@ class UnoConverter: """ def __init__(self, interface="127.0.0.1", port="2002"): - logger.info("Starting unoconverter.") + logger.info("Starting UnoConverter.") self.local_context = uno.getComponentContext() self.resolver = self.local_context.ServiceManager.createInstanceWithContext( diff --git a/src/unoserver/server.py b/src/unoserver/server.py index c68c6aa..1cad45b 100644 --- a/src/unoserver/server.py +++ b/src/unoserver/server.py @@ -55,6 +55,7 @@ def __init__( self.libreoffice_process = None self.xmlrcp_thread = None self.xmlrcp_server = None + self.intentional_exit = False def start(self, executable="libreoffice"): import time @@ -86,6 +87,7 @@ def start(self, executable="libreoffice"): self.xmlrcp_thread = threading.Thread(None, self.serve) def signal_handler(signum, frame): + self.intentional_exit = True logger.info("Sending signal to LibreOffice") try: self.libreoffice_process.send_signal(signum) @@ -108,6 +110,14 @@ def signal_handler(signum, frame): self.xmlrcp_thread.start() + # Give the thread time to start + time.sleep(2) + # Check if it suceeded + if not self.xmlrcp_thread.is_alive(): + logger.info("Failed to start servers") + self.stop() + return None + return self.libreoffice_process def serve(self): @@ -193,7 +203,9 @@ def stop(self): # hang indefinitely in the accept() call. # noinspection PyBroadException try: - with socket.create_connection((self.interface, int(self.port)), timeout=1): + with socket.create_connection( + (self.interface, int(self.port)), timeout=1 + ): pass except Exception: pass # Ignore any except @@ -276,6 +288,8 @@ def main(): # It returns 0 of getting killed in a normal way. # Otherwise it returns 1 after the process exits. process = server.start(executable=args.executable) + if process is None: + return 2 pid = process.pid logger.info(f"Server PID: {pid}") @@ -286,6 +300,9 @@ def main(): process.wait() + if not server.intentional_exit: + logger.error(f"Looks like LibreOffice died. PID: {pid}") + # The RPC thread needs to be stopped before the process can exit server.stop() @@ -296,8 +313,11 @@ def main(): try: # Make sure it's really dead os.kill(pid, 0) - # It was killed - return 0 + + if server.intentional_exit: + return 0 + else: + return 1 except OSError as e: if e.errno == 3: # All good, it was already dead.