graceful exit
This commit is contained in:
@@ -1,10 +1,38 @@
|
||||
import logging
|
||||
from flask import Flask
|
||||
from .config import Config
|
||||
from .extensions import init_extensions, register_namespaces
|
||||
from .extensions import init_extensions, register_namespaces, close_extensions
|
||||
from .views import register_blueprints
|
||||
import atexit
|
||||
import logging
|
||||
import signal
|
||||
import threading
|
||||
|
||||
_shutdown_once = threading.Event()
|
||||
|
||||
def _graceful_shutdown(app: Flask, signum: str = "atexit"):
|
||||
# 防止重复执行
|
||||
if _shutdown_once.is_set():
|
||||
return
|
||||
_shutdown_once.set()
|
||||
|
||||
app.logger.info("Shutting down gracefully (%s)...", signum)
|
||||
try:
|
||||
close_extensions()
|
||||
finally:
|
||||
app.logger.info("Cleanup finished (%s).", signum)
|
||||
|
||||
def _bind_signals(app: Flask):
|
||||
def handler(sig, frame):
|
||||
_graceful_shutdown(app, signum=sig)
|
||||
# 不要在这里强行 os._exit(0),让外层管理器决定何时真正退出
|
||||
for s in (signal.SIGINT, signal.SIGTERM, getattr(signal, "SIGQUIT", None)):
|
||||
if s is not None:
|
||||
try:
|
||||
signal.signal(s, handler)
|
||||
except Exception:
|
||||
# 某些环境不能重绑定(如部分 WSGI 容器内),忽略
|
||||
pass
|
||||
|
||||
def create_app(config_object: type = Config) -> Flask:
|
||||
app = Flask(__name__, template_folder="templates", static_folder="static")
|
||||
@@ -31,4 +59,9 @@ def create_app(config_object: type = Config) -> Flask:
|
||||
def healthz():
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
# 绑定退出钩子(开发/简单部署环境很有用)
|
||||
atexit.register(_graceful_shutdown, app, "atexit")
|
||||
_bind_signals(app)
|
||||
|
||||
return app
|
||||
|
||||
@@ -248,3 +248,5 @@ class ChatManager:
|
||||
keys = list(self._procs.keys())
|
||||
for k in keys:
|
||||
self.stop(k)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from flask_pymongo import PyMongo
|
||||
from qcloud_cos import CosConfig
|
||||
from qcloud_cos import CosS3Client
|
||||
|
||||
from typing import Optional
|
||||
|
||||
mongo = PyMongo()
|
||||
|
||||
@@ -77,3 +78,14 @@ def register_namespaces(app):
|
||||
from .sockets.namespaces import VSCodeNamespace, AgentNamespace
|
||||
socketio.on_namespace(VSCodeNamespace("/vscode"))
|
||||
socketio.on_namespace(AgentNamespace("/agent"))
|
||||
|
||||
|
||||
def close_extensions():
|
||||
# 按“最可能阻塞”的优先级依次停止
|
||||
try:
|
||||
if user_uuid2chatmanager:
|
||||
for uuid in user_uuid2chatmanager:
|
||||
user_uuid2chatmanager[uuid].disconnect(uuid)
|
||||
except Exception as e:
|
||||
print("Failed to shutdown scheduler: %s", e)
|
||||
|
||||
Reference in New Issue
Block a user