Parent: #6(生命周期审计发现,先登记再修)
症状
lifespan 停机序列(main.py:418-444)整体无超时上限,且有两处「一步异常/挂住即跳过余下清理」:
- main.py:419-422 —
_cache_warmup_task cancel 后仅 suppress(CancelledError):若任务以非取消异常完成,await 再抛 → 跳过调度器停机、兴趣向量 drain、DuckDB 关闭、engine.dispose 全部后续步骤。
- main.py:423-424 — jieba 预热 task await 无超时,且底层
asyncio.to_thread 不可取消 → 词典加载卡住可无限挂住停机。
另:shutdown_scheduler 的 scheduler.shutdown(wait=True) 无 deadline(scheduler.py:1227),wait=False 降级仅在 shutdown 自身抛异常时触发。
期望 vs 实际
优雅停机应每步有界且互不中断:单步失败记日志后继续清理,整体有 deadline。
边界
lifespan shutdown / 调度器 / DuckDB / engine 释放顺序。
严重度 / 复现性
P2 / 停机时预热任务带异常或 jieba 慢加载时触发。
回归测试候选
停机序各步异常隔离(step fails → 后续仍执行)、jieba await 超时路径。
日志/证据
审计第一路报告(见 #6)。
Parent: #6(生命周期审计发现,先登记再修)
症状
lifespan 停机序列(main.py:418-444)整体无超时上限,且有两处「一步异常/挂住即跳过余下清理」:
_cache_warmup_taskcancel 后仅suppress(CancelledError):若任务以非取消异常完成,await 再抛 → 跳过调度器停机、兴趣向量 drain、DuckDB 关闭、engine.dispose 全部后续步骤。asyncio.to_thread不可取消 → 词典加载卡住可无限挂住停机。另:
shutdown_scheduler的scheduler.shutdown(wait=True)无 deadline(scheduler.py:1227),wait=False 降级仅在 shutdown 自身抛异常时触发。期望 vs 实际
优雅停机应每步有界且互不中断:单步失败记日志后继续清理,整体有 deadline。
边界
lifespan shutdown / 调度器 / DuckDB / engine 释放顺序。
严重度 / 复现性
P2 / 停机时预热任务带异常或 jieba 慢加载时触发。
回归测试候选
停机序各步异常隔离(step fails → 后续仍执行)、jieba await 超时路径。
日志/证据
审计第一路报告(见 #6)。