From 39b5448fc3f020fe39c7b9020d8c643ca6819266 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Tue, 23 Apr 2024 18:28:35 +0200 Subject: [PATCH] If FastAPI server failed to start, Glances do not return a critical error #2675 --- glances/outputs/glances_restful_api.py | 45 ++++++++++++++++++++++++-- glances/webserver.py | 1 + 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/glances/outputs/glances_restful_api.py b/glances/outputs/glances_restful_api.py index ca8da563..35935c77 100644 --- a/glances/outputs/glances_restful_api.py +++ b/glances/outputs/glances_restful_api.py @@ -43,10 +43,37 @@ try: except ImportError: logger.critical('Uvicorn import error. Glances cannot start in web server mode.') sys.exit(2) +import contextlib +import threading +import time security = HTTPBasic() +class GlancesUvicornServer(uvicorn.Server): + def install_signal_handlers(self): + pass + + @contextlib.contextmanager + def run_in_thread(self, timeout=3): + thread = threading.Thread(target=self.run) + thread.start() + try: + chrono = Timer(timeout) + while not self.started and not chrono.finished(): + time.sleep(0.5) + # Timeout reached + # Something go wrong... + # The Uvicorn server should be stopped + if not self.started: + self.should_exit = True + thread.join() + yield + finally: + self.should_exit = True + thread.join() + + class GlancesRestfulApi(object): """This class manages the Restful API server.""" @@ -269,11 +296,23 @@ class GlancesRestfulApi(object): # 2) Glances standalone mode is running on Windows OS webbrowser.open(self.bind_url, new=2, autoraise=1) - # Run the Web application + # Start Uvicorn server + self._start_uvicorn() + + def _start_uvicorn(self): + # Run the Uvicorn Web server + uvicorn_config = uvicorn.Config(self._app, + host=self.args.bind_address, port=self.args.port, + access_log=self.args.debug) try: - uvicorn.run(self._app, host=self.args.bind_address, port=self.args.port, access_log=self.args.debug) - except socket.error as e: + self.uvicorn_server = GlancesUvicornServer(config=uvicorn_config) + except Exception as e: logger.critical('Error: Can not ran Glances Web server ({})'.format(e)) + self.uvicorn_server = None + else: + with self.uvicorn_server.run_in_thread(): + while not self.uvicorn_server.should_exit: + time.sleep(1) def end(self): """End the Web server""" diff --git a/glances/webserver.py b/glances/webserver.py index 44c24ec2..e61ca32b 100644 --- a/glances/webserver.py +++ b/glances/webserver.py @@ -9,6 +9,7 @@ """Glances Restful/API and Web based interface.""" +from glances.logger import logger from glances.globals import WINDOWS from glances.processes import glances_processes from glances.stats import GlancesStats