Files
kami_apple_exchage/backend/docs/GRACEFUL_SHUTDOWN.md
danial 8ad2a5366a refactor(backend): 将Celery替换为Arq进行协程任务处理
本次提交将后端的任务队列系统从Celery迁移到了Arq,以支持基于协程的任务处理。主要改动包括:
- 更新文档和配置文件,反映架构变化。
- 修改健康检查和服务初始化逻辑,以适应Arq的使用。
- 移除与Celery相关的代码,并添加Arq任务定义和调度器。
- 更新Dockerfile和相关脚本,确保Arq worker能够正确运行。
- 调整API和业务服务中的任务处理逻辑,移除对Celery的依赖。

这些改动旨在提高系统的异步处理能力和整体性能。
2025-09-18 16:02:05 +08:00

5.6 KiB
Raw Blame History

优雅关闭功能集成指南

概述

本项目已集成优雅关闭功能,确保在收到关闭信号时能够:

  • 保存正在运行的任务状态
  • 等待活跃请求完成
  • 安全关闭数据库连接
  • 清理临时资源
  • 记录关闭状态

功能特性

🚀 Web 服务优雅关闭

  • 自动等待所有活跃 HTTP 请求完成
  • 保存系统状态到文件
  • 安全关闭数据库和 OpenTelemetry 连接
  • 支持 30 秒超时保护

🔧 Arq Worker 优雅关闭

  • 自动保存正在运行的任务状态为 "PAUSED"
  • 清理 Playwright 浏览器资源
  • 支持任务恢复机制
  • 记录任务中断原因

📊 状态管理

  • 将运行中任务标记为可恢复的暂停状态
  • 保存关闭时间和进程信息
  • 支持后续任务恢复

使用方法

1. 启动 Web 服务

使用内置的优雅关闭启动脚本:

# 启动 Web 服务(推荐)
python scripts/run_with_graceful_shutdown.py web

# 启动 Web 服务(调试模式)
python scripts/run_with_graceful_shutdown.py web --debug

或者直接使用原有方式(已自动集成):

# 标准启动方式
uvicorn app.main:app --host 0.0.0.0 --port 8000

# 开发模式
python app/main.py

2. 启动 Arq Worker

# 启动 Worker推荐
python scripts/run_with_graceful_shutdown.py worker

# 或直接使用 Arq 命令
uv run python -m arq app.core.arq_worker:ArqWorkerSettings

3. 开发模式Web + Worker

# 同时启动 Web 服务和 Worker
python scripts/run_with_graceful_shutdown.py dev

信号处理

支持以下信号进行优雅关闭:

  • SIGTERM - 终止信号Docker、Kubernetes 默认)
  • SIGINT - 中断信号Ctrl+C
  • SIGHUP - 挂起信号Linux/Mac

关闭流程

  1. 接收信号 → 设置关闭标志
  2. 保存状态 → 将运行中任务标记为暂停
  3. 等待请求 → 最多等待 30 秒活跃请求完成
  4. 执行回调 → 依次执行注册的关闭回调
  5. 清理资源 → 清理临时文件和缓存
  6. 安全退出 → 记录关闭完成并退出

任务恢复

当系统重启后,可以通过以下方式恢复被中断的任务:

from app.core.state_manager import task_state_manager

# 获取被暂停的任务
paused_tasks = await task_state_manager.state_manager.list_states(StateType.TASK)
interrupted_tasks = [
    task for task in paused_tasks 
    if task.get("status") == "PAUSED" 
    and task.get("interrupt_reason") == "graceful_shutdown"
]

# 恢复任务
for task in interrupted_tasks:
    task_id = task.get("identifier")
    if task_id:
        # 重新提交任务或更新状态为 PENDING
        await task_state_manager.set_task_state(
            task_id, 
            OrderTaskStatus.PENDING,
            progress=task.get("progress", 0.0)
        )

配置选项

可以通过修改 GracefulShutdownManager 来调整配置:

from app.core.graceful_shutdown import graceful_shutdown_manager

# 设置关闭超时时间(默认 30 秒)
graceful_shutdown_manager.shutdown_timeout = 60

# 注册自定义关闭回调
async def custom_cleanup():
    # 自定义清理逻辑
    pass

graceful_shutdown_manager.register_shutdown_callback(custom_cleanup)

状态文件

关闭状态会保存到 ./data/state/ 目录:

{
  "shutdown_time": "2024-01-15T10:30:00.000Z",
  "shutdown_type": "graceful",
  "process_id": 12345,
  "active_requests_count": 2
}

Docker / Kubernetes 部署

Dockerfile 配置

确保容器能正确处理信号:

# 使用 exec 形式确保信号正确传递
CMD ["python", "scripts/run_with_graceful_shutdown.py", "web"]

# 或者
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Kubernetes 配置

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      terminationGracePeriodSeconds: 45  # 给予充足的关闭时间
      containers:
      - name: app
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 5"]  # 可选:额外延迟

监控和日志

优雅关闭过程会产生详细的日志:

INFO - 接收到信号 SIGTERM (15),开始优雅关闭...
INFO - 开始执行异步关闭流程...
INFO - 保存当前任务状态...
INFO - 已将 3 个正在运行的任务标记为暂停状态
INFO - 等待 2 个活跃请求完成... (5.0s/30s)
INFO - 所有活跃请求已完成
INFO - 清理系统资源...
INFO - 优雅关闭完成,退出程序

故障排除

常见问题

  1. 关闭超时

    • 检查是否有长时间运行的请求
    • 调整 shutdown_timeout 参数
    • 查看日志中的活跃请求数量
  2. 任务状态丢失

    • 确认 Redis 连接正常
    • 检查任务状态管理器是否正确初始化
    • 查看错误日志
  3. 信号未响应

    • 确认进程以正确方式启动
    • 检查是否在信号处理器设置前收到信号
    • 验证 Docker/K8s 信号传递配置

调试模式

启用调试日志查看详细流程:

export LOG_LEVEL=DEBUG
python scripts/run_with_graceful_shutdown.py web

最佳实践

  1. 总是使用推荐的启动脚本
  2. 为 Kubernetes 设置合适的 terminationGracePeriodSeconds
  3. 监控关闭日志确保流程正常
  4. 定期测试任务恢复机制
  5. 在生产环境中设置适当的超时时间

相关文件

  • app/core/graceful_shutdown.py - 优雅关闭核心实现
  • app/main.py - Web 服务集成
  • app/core/arq_worker.py - Arq Worker 集成
  • app/core/worker_init.py - Worker 初始化集成
  • scripts/run_with_graceful_shutdown.py - 启动脚本