1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-25 01:38:08 +00:00

Detect the app is exiting and avoid reconnecting to computes.

This commit is contained in:
grossmj 2021-04-17 18:33:20 +09:30
parent 6b8ce8219c
commit bad3ef7003
4 changed files with 19 additions and 13 deletions

View File

@ -25,7 +25,7 @@ from fastapi import FastAPI, Request
from starlette.exceptions import HTTPException as StarletteHTTPException from starlette.exceptions import HTTPException as StarletteHTTPException
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from uvicorn.main import Server as UvicornServer
from gns3server.controller.controller_error import ( from gns3server.controller.controller_error import (
ControllerError, ControllerError,
@ -82,6 +82,18 @@ def get_application() -> FastAPI:
app = get_application() app = get_application()
# Monkey Patch uvicorn signal handler to detect the application is shutting down
app.state.exiting = False
unicorn_exit_handler = UvicornServer.handle_exit
def handle_exit(*args, **kwargs):
app.state.exiting = True
unicorn_exit_handler(*args, **kwargs)
UvicornServer.handle_exit = handle_exit
@app.exception_handler(ControllerError) @app.exception_handler(ControllerError)
async def controller_error_handler(request: Request, exc: ControllerError): async def controller_error_handler(request: Request, exc: ControllerError):

View File

@ -21,7 +21,6 @@ import asyncio
import async_timeout import async_timeout
import socket import socket
import json import json
import uuid
import sys import sys
import io import io
from operator import itemgetter from operator import itemgetter
@ -295,6 +294,7 @@ class Compute:
""" """
:param topology_dump: Filter to keep only properties require for saving on disk :param topology_dump: Filter to keep only properties require for saving on disk
""" """
if topology_dump: if topology_dump:
return { return {
"compute_id": self._id, "compute_id": self._id,
@ -486,7 +486,8 @@ class Compute:
log.info(f"Connection closed to compute '{self._id}' WebSocket '{ws_url}'") 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 ressources usage bomb)
if self.id != "local" and not hasattr(sys, "_called_from_test") or not sys._called_from_test: from gns3server.api.server import app
if not app.state.exiting and not hasattr(sys, "_called_from_test") or not sys._called_from_test:
log.info(f"Reconnecting to to compute '{self._id}' WebSocket '{ws_url}'") log.info(f"Reconnecting to to compute '{self._id}' WebSocket '{ws_url}'")
asyncio.get_event_loop().call_later(1, lambda: asyncio.ensure_future(self.connect())) asyncio.get_event_loop().call_later(1, lambda: asyncio.ensure_future(self.connect()))

View File

@ -82,7 +82,7 @@ def create_startup_handler(app: FastAPI) -> Callable:
def create_shutdown_handler(app: FastAPI) -> Callable: def create_shutdown_handler(app: FastAPI) -> Callable:
""" """
Tasks to be performed when the server is shutdown. Tasks to be performed when the server is exiting.
""" """
async def shutdown_handler() -> None: async def shutdown_handler() -> None:

View File

@ -38,7 +38,6 @@ from gns3server.version import __version__
from gns3server.config import Config from gns3server.config import Config
from gns3server.crash_report import CrashReport from gns3server.crash_report import CrashReport
from gns3server.api.server import app from gns3server.api.server import app
from pydantic import ValidationError from pydantic import ValidationError
import logging import logging
@ -170,22 +169,16 @@ class Server:
config.Server.certkey = args.certkey config.Server.certkey = args.certkey
config.Server.enable_ssl = args.ssl config.Server.enable_ssl = args.ssl
async def reload_server(self):
"""
Reload the server.
"""
await Controller.instance().reload()
def _signal_handling(self): def _signal_handling(self):
def signal_handler(signame, *args): def signal_handler(signame, *args):
try: try:
if signame == "SIGHUP": if signame == "SIGHUP":
log.info(f"Server has got signal {signame}, reloading...") log.info(f"Server has got signal {signame}, reloading...")
asyncio.ensure_future(self.reload_server()) asyncio.ensure_future(Controller.instance().reload())
else: else:
log.info(f"Server has got signal {signame}, exiting...") log.info(f"Server has got signal {signame}, exiting...")
# send SIGTERM to the server PID so uvicorn can shutdown the process
os.kill(os.getpid(), signal.SIGTERM) os.kill(os.getpid(), signal.SIGTERM)
except asyncio.CancelledError: except asyncio.CancelledError:
pass pass