细节优化
This commit is contained in:
+53
-1
@@ -18,7 +18,7 @@ from app.api.knowledge_bases import router as kb_router
|
||||
from app.public.routes import router as public_router
|
||||
from app.core.config import get_settings
|
||||
from app.core.db import dispose_engine, get_session_factory
|
||||
from app.core.errors import register_exception_handlers
|
||||
from app.core.errors import LinkExpiredError, register_exception_handlers
|
||||
from app.core.logging import get_logger, setup_logging
|
||||
|
||||
logger = get_logger(__name__)
|
||||
@@ -40,6 +40,43 @@ def _seed_free_plan() -> None:
|
||||
logger.debug("Free plan already exists (id=%s)", plan.id)
|
||||
|
||||
|
||||
def _cleanup_access_logs() -> int:
|
||||
"""清理超过保留期的访问日志。返回删除条数。"""
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from sqlalchemy import delete
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.models.access_log import AccessLog
|
||||
|
||||
settings = get_settings()
|
||||
retention = settings.access_log_retention_days
|
||||
if retention <= 0:
|
||||
return 0
|
||||
|
||||
cutoff = (datetime.now() - timedelta(days=retention)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
factory = get_session_factory()
|
||||
with factory() as session:
|
||||
result = session.execute(delete(AccessLog).where(AccessLog.accessed_at < cutoff))
|
||||
session.commit()
|
||||
count = result.rowcount or 0
|
||||
if count:
|
||||
logger.info("已清理 %d 条过期访问日志(保留 %d 天)", count, retention)
|
||||
return count
|
||||
|
||||
|
||||
async def _periodic_log_cleanup() -> None:
|
||||
"""每 24 小时清理一次过期访问日志(在线程池执行同步 DB 操作)。"""
|
||||
import asyncio
|
||||
|
||||
while True:
|
||||
await asyncio.sleep(24 * 3600)
|
||||
try:
|
||||
await asyncio.to_thread(_cleanup_access_logs)
|
||||
except Exception: # noqa: BLE001
|
||||
logger.exception("定期清理访问日志失败")
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
settings = get_settings()
|
||||
@@ -53,8 +90,18 @@ async def lifespan(app: FastAPI):
|
||||
# Seed:确保 free plan 存在
|
||||
_seed_free_plan()
|
||||
|
||||
# 启动时清理过期访问日志(不阻塞启动)
|
||||
import asyncio
|
||||
|
||||
cleanup_task = asyncio.create_task(_periodic_log_cleanup())
|
||||
try:
|
||||
await asyncio.wait_for(asyncio.to_thread(_cleanup_access_logs), timeout=15)
|
||||
except Exception: # noqa: BLE001
|
||||
logger.warning("启动时清理访问日志未完成(首次部署属正常)")
|
||||
|
||||
yield
|
||||
|
||||
cleanup_task.cancel()
|
||||
dispose_engine()
|
||||
logger.info("Backend shutdown complete")
|
||||
|
||||
@@ -80,6 +127,11 @@ def create_app() -> FastAPI:
|
||||
|
||||
register_exception_handlers(app)
|
||||
|
||||
# 链接过期:HTML 返回友好失效页,JSON/MD/TXT 返回对应格式(HTTP 410)
|
||||
from app.public.routes import link_expired_handler
|
||||
|
||||
app.add_exception_handler(LinkExpiredError, link_expired_handler)
|
||||
|
||||
# 路由挂载
|
||||
app.include_router(health_router, prefix="/api", tags=["health"])
|
||||
app.include_router(auth_router, prefix="/api", tags=["auth"])
|
||||
|
||||
Reference in New Issue
Block a user