Compare commits

...

4 Commits

Author SHA1 Message Date
liangtianyu
25a016977c 不处理退出信号 2025-12-14 20:20:30 +08:00
mark.tian
8541dc77ec Merge branch 'main' of https://git.shiliulizi.cn/mark.tian/ai-talk-callback 2025-12-13 13:43:04 +08:00
mark.tian
666a073475 增加全局未处理异常处理 2025-12-13 13:42:29 +08:00
mark.tian
3337c751a5 增加全局未处理异常的处理 2025-12-13 13:41:59 +08:00

106
main.py
View File

@@ -1,19 +1,20 @@
from datetime import datetime
import os
import traceback
import signal import signal
import tempfile import tempfile
import time import time
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
from sqlalchemy import text
import redis.asyncio as redis
import subprocess import subprocess
import sys import sys
import os
from app.config import settings from app.config import settings
from app.database import engine from app.database import engine
from app.routes import router from app.routes import router
from app.logger import LoggerManager, get_main_logger from app.logger import LoggerManager, get_main_logger
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import redis.asyncio as redis
from sqlalchemy import text
# 初始化日志系统 # 初始化日志系统
@@ -21,6 +22,31 @@ LoggerManager.setup_logging()
logger = get_main_logger() logger = get_main_logger()
def global_exception_handler(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt):
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
# 获取格式化的异常信息
error_msg = "捕获到未处理的异常:\n"
error_msg += f"异常类型: {exc_type.__name__}\n"
error_msg += f"异常信息: {exc_value}\n"
error_msg += "堆栈跟踪:\n"
error_msg += "".join(traceback.format_tb(exc_traceback))
error_msg += f"异常时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n"
error_msg += "-" * 50 + "\n"
# 输出到控制台
print(error_msg)
# 输出到文件
logger.error(error_msg)
# 注册全局异常处理器
sys.excepthook = global_exception_handler
@asynccontextmanager @asynccontextmanager
async def lifespan(app: FastAPI): async def lifespan(app: FastAPI):
# 启动时初始化 # 启动时初始化
@@ -144,6 +170,7 @@ async def health_check():
# 全局变量存储进程 # 全局变量存储进程
processes = [] processes = []
def signal_handler(signum, frame): def signal_handler(signum, frame):
"""信号处理器,用于优雅关闭所有服务""" """信号处理器,用于优雅关闭所有服务"""
print(f"\n🛑 接收到信号 {signum},正在关闭所有服务...") print(f"\n🛑 接收到信号 {signum},正在关闭所有服务...")
@@ -165,6 +192,7 @@ def signal_handler(signum, frame):
print("👋 所有服务已关闭") print("👋 所有服务已关闭")
sys.exit(0) sys.exit(0)
def start_all_services(): def start_all_services():
"""启动所有服务""" """启动所有服务"""
global processes global processes
@@ -173,34 +201,44 @@ def start_all_services():
print("=" * 60) print("=" * 60)
# 注册信号处理器 # 注册信号处理器
signal.signal(signal.SIGINT, signal_handler) # Ctrl+C # signal.signal(signal.SIGINT, signal_handler) # Ctrl+C
signal.signal(signal.SIGTERM, signal_handler) # 终止信号 # signal.signal(signal.SIGTERM, signal_handler) # 终止信号
try: try:
# 1. 启动 Celery Worker # 1. 启动 Celery Worker
print("🌿 启动 Celery Worker...") print("🌿 启动 Celery Worker...")
worker_process = subprocess.Popen([ worker_process = subprocess.Popen(
sys.executable, "-m", "celery", [
"-A", "app.celery_app", sys.executable,
"-m",
"celery",
"-A",
"app.celery_app",
"worker", "worker",
'--loglevel=info', "--loglevel=info",
'--pool=solo', "--pool=solo",
'--concurrency=1', "--concurrency=1",
'--time-limit=300', # 5分钟任务超时 "--time-limit=300", # 5分钟任务超时
'--soft-time-limit=240' # 4分钟软超时 "--soft-time-limit=240", # 4分钟软超时
]) ]
)
processes.append(worker_process) processes.append(worker_process)
time.sleep(2) # 等待 Worker 启动 time.sleep(2) # 等待 Worker 启动
# 2. 启动 Celery Beat # 2. 启动 Celery Beat
print("\n📅 启动 Celery Beat...") print("\n📅 启动 Celery Beat...")
beat_process = subprocess.Popen([ beat_process = subprocess.Popen(
sys.executable, "-m", "celery", [
"-A", "app.celery_app", sys.executable,
"-m",
"celery",
"-A",
"app.celery_app",
"beat", "beat",
'--loglevel=info', "--loglevel=info",
f'--schedule={os.path.join(tempfile.gettempdir(), "celerybeat-schedule")}' f'--schedule={os.path.join(tempfile.gettempdir(), "celerybeat-schedule")}',
]) ]
)
processes.append(beat_process) processes.append(beat_process)
time.sleep(2) # 等待 Beat 启动 time.sleep(2) # 等待 Beat 启动
@@ -208,11 +246,14 @@ def start_all_services():
if settings.flower_enabled: if settings.flower_enabled:
print("\n📊 启动 Flower 监控服务...") print("\n📊 启动 Flower 监控服务...")
flower_cmd = [ flower_cmd = [
sys.executable, "-m", "celery", sys.executable,
"-A", "app.celery_app", "-m",
"celery",
"-A",
"app.celery_app",
f"--broker={settings.celery_broker_url}", f"--broker={settings.celery_broker_url}",
"flower", "flower",
f"--port={settings.flower_port}" f"--port={settings.flower_port}",
] ]
if settings.flower_basic_auth: if settings.flower_basic_auth:
@@ -227,10 +268,14 @@ def start_all_services():
# 4. 启动 FastAPI 应用 # 4. 启动 FastAPI 应用
print("\n🚀 启动 FastAPI 应用...") print("\n🚀 启动 FastAPI 应用...")
api_cmd = [ api_cmd = [
sys.executable, "-m", "uvicorn", sys.executable,
"-m",
"uvicorn",
"main:app", "main:app",
"--host", "0.0.0.0", "--host",
"--port", "8000" "0.0.0.0",
"--port",
"8000",
] ]
# 添加调试模式(如果配置了) # 添加调试模式(如果配置了)
@@ -269,6 +314,7 @@ def start_all_services():
print(f"❌ 启动服务时出错: {e}") print(f"❌ 启动服务时出错: {e}")
signal_handler(signal.SIGINT, None) signal_handler(signal.SIGINT, None)
if __name__ == "__main__": if __name__ == "__main__":
# 直接启动所有服务 # 直接启动所有服务
start_all_services() start_all_services()