From 0a118dc9e778a464f7cc82a42b25b978b7ddf9e0 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 16 Feb 2026 19:16:06 +0800 Subject: [PATCH] Cancel tasks if controller cannot be started --- gns3server/controller/__init__.py | 9 ++++++++- gns3server/controller/compute.py | 2 +- gns3server/core/tasks.py | 12 +++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/gns3server/controller/__init__.py b/gns3server/controller/__init__.py index 539121a42..26435b6d8 100644 --- a/gns3server/controller/__init__.py +++ b/gns3server/controller/__init__.py @@ -68,6 +68,7 @@ class Controller: self._iou_license_settings = {"iourc_content": "", "license_check": False} self._vars_loaded = False self._vars_file = Config.instance().controller_vars + self._project_auto_open_task_handle = None log.info(f'Loading controller vars file "{self._vars_file}"') async def start(self, computes=None): @@ -141,7 +142,11 @@ class Controller: await self.load_projects() # start to auto open projects (if configured) 5 seconds after the controller has started - asyncio.get_event_loop().call_later(5, asyncio.create_task, self._project_auto_open()) + self._project_auto_open_task_handle = asyncio.get_event_loop().call_later( + 5, + lambda: asyncio.create_task(self._project_auto_open()) + ) + def _create_ssl_context(self, server_config): @@ -179,6 +184,8 @@ class Controller: async def stop(self): log.info("Controller is stopping") + if self._project_auto_open_task_handle is not None and not self._project_auto_open_task_handle.cancelled(): + self._project_auto_open_task_handle.cancel() for project in self._projects.values(): await project.close() for compute in self._computes.values(): diff --git a/gns3server/controller/compute.py b/gns3server/controller/compute.py index c01fddaef..65bca3c34 100644 --- a/gns3server/controller/compute.py +++ b/gns3server/controller/compute.py @@ -478,7 +478,7 @@ class Compute: self._connected = False log.info(f"Connection closed to compute '{self._id}' WebSocket '{ws_url}'") - # Try to reconnect after 1 second if server unavailable only if not during tests (otherwise we create a ressources usage bomb) + # Try to reconnect after 1 second if server unavailable only if not during tests (otherwise we create a resources usage bomb) from gns3server.api.server import app if not app.state.exiting and not hasattr(sys, "_called_from_test"): log.info(f"Reconnecting to compute '{self._id}' WebSocket '{ws_url}'") diff --git a/gns3server/core/tasks.py b/gns3server/core/tasks.py index 24de59405..ebc62d52c 100644 --- a/gns3server/core/tasks.py +++ b/gns3server/core/tasks.py @@ -32,6 +32,8 @@ import logging log = logging.getLogger(__name__) +auto_discover_images_task_handle = None + def create_startup_handler(app: FastAPI) -> Callable: """ @@ -64,7 +66,11 @@ def create_startup_handler(app: FastAPI) -> Callable: if Config.instance().settings.Server.auto_discover_images is True: # Start the discovering new images on file system 5 seconds after the server has started # to give it a chance to process API requests - loop.call_later(5, asyncio.create_task, discover_images_on_filesystem(app)) + global auto_discover_images_task_handle + auto_discover_images_task_handle = asyncio.get_event_loop().call_later( + 5, + lambda: asyncio.create_task(discover_images_on_filesystem(app)) + ) for module in MODULES: log.debug(f"Loading module {module.__name__}") @@ -80,6 +86,10 @@ def create_shutdown_handler(app: FastAPI) -> Callable: """ async def shutdown_handler() -> None: + + global auto_discover_images_task_handle + if auto_discover_images_task_handle is not None and not auto_discover_images_task_handle.cancelled(): + auto_discover_images_task_handle.cancel() await HTTPClient.close_session() await Controller.instance().stop()