graceful exit

This commit is contained in:
CakeCN
2025-09-13 15:30:18 +08:00
parent 2087776e40
commit b1e132db8d
3 changed files with 50 additions and 3 deletions

View File

@@ -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

View File

@@ -248,3 +248,5 @@ class ChatManager:
keys = list(self._procs.keys())
for k in keys:
self.stop(k)

View File

@@ -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)