Skip to content

优雅关闭

说明

优雅关闭确保应用在收到终止信号时,能够完成正在处理的请求、关闭数据库连接、停止定时任务调度器后再退出,避免请求中断和资源泄漏。

工作原理

收到 SIGINT / SIGTERM 信号

   ├─ 停止接收新请求
   ├─ 关闭定时任务调度器(shutdown_scheduler)
   ├─ 停止 IOLoop 事件循环
   └─ 进程退出

实现

python
# src/bootstrap.py
import signal
import tornado.httpserver
import tornado.ioloop

def main():
    app = create_app()
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)

    # 启动定时任务调度器
    from modules.job.scheduler import init_scheduler
    init_scheduler()

    ioloop = tornado.ioloop.IOLoop.current()

    # ============================================================
    # 优雅关闭回调
    # ============================================================
    def _shutdown():
        """收到退出信号时关闭调度器并停止事件循环。"""
        logger.info("收到退出信号,正在优雅关闭...")
        from modules.job.scheduler import shutdown_scheduler
        shutdown_scheduler()
        ioloop.stop()

    # ============================================================
    # 注册信号处理(优雅关闭)
    # ============================================================
    for sig in (signal.SIGINT, signal.SIGTERM):
        try:
            signal.signal(sig, lambda s, f: ioloop.add_callback_from_signal(_shutdown))
        except (ValueError, AttributeError, OSError):
            pass

    ioloop.start()

信号说明

信号触发方式说明
SIGINTCtrl+C终端中断信号
SIGTERMkill <pid>进程终止信号(Docker/Supervisor 默认发送)

Windows 兼容

Windows 下 SIGTERM 可能不完全支持,SIGINT(Ctrl+C)是主要的关闭方式。代码中使用 try/except 包裹信号注册,避免 Windows 下的兼容性问题。

关闭顺序

  1. 停止定时任务调度器shutdown_scheduler() 停止 APScheduler,等待正在执行的任务完成
  2. 停止 IOLoopioloop.stop() 停止事件循环,进程自然退出
  3. BaseHandler.on_finish:每个请求结束后自动关闭 DB 会话(兜底释放)

Docker 中的使用

Docker 发送 SIGTERM 等待 30 秒后发送 SIGKILL

dockerfile
# Dockerfile
STOPSIGNAL SIGTERM
yaml
# docker-compose.yml
services:
  app:
    stop_grace_period: 30s

Supervisor 中的使用

ini
[program:djangoadmin]
command=poetry run python app.py --port=8041
stopsignal=TERM
stopwaitsecs=30

总结

优雅关闭方案具备以下特点:

1. 信号驱动:SIGINT / SIGTERM 触发关闭流程
2. 调度器先停:先关闭定时任务,避免任务执行到一半
3. IOLoop 停止:事件循环停止后进程自然退出
4. DB 会话兜底:BaseHandler.on_finish 确保会话释放
5. 容器友好:Docker / Supervisor 默认发送 SIGTERM

小蚂蚁云团队 · 提供技术支持