mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-24 17:28:08 +00:00
Detect the app is exiting and avoid reconnecting to computes.
This commit is contained in:
parent
6b8ce8219c
commit
bad3ef7003
@ -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):
|
||||||
|
@ -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()))
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user