bigywater.tech
Flask · 180

优雅关闭

部署新版本时,正在处理的请求会怎么样?不同信号对 gunicorn 的效果差别很大。这篇用真实的 gunicorn,让一个 3 秒的请求处于进行中,逐个发信号,看请求结果、退出时间、atexit 和 worker_exit 钩子(容器里的信号传递见第 189 篇)。

3.01 s
SIGTERM 时进行中的 3 秒请求正常完成
500
SIGINT / SIGQUIT 时进行中的请求得到的状态码
0 / 62
SIGHUP 重载期间失败的探测请求数

SIGTERM

实测 · 本机执行输出
  那个进行中的请求 → 200 done by 7258,耗时 3.01 s | 关闭开始 0.5 秒后的新连接 → ConnectionResetError | master 退出用了 2.66 s
  日志:
    [2026-10-02 15:49:53 +0800] [72585] [INFO] Booting worker with pid: 72585
    [2026-10-02 15:49:54 +0800] [72583] [INFO] Handling signal: term
    [2026-10-02 15:49:56 +0800] [72585] [INFO] Worker exiting (pid: 72585)
    [2026-10-02 15:49:56 +0800] [72583] [INFO] Shutting down: Master
  worker 里 atexit 是否运行: ['atexit in pid 72585'] | worker_exit 钩子: ['worker_exit hook pid 72585']

上一篇:健康检查接口;下一篇:日志配置。

实验用 1 个 sync worker 与 2 个 worker 两种配置,请求是 time.sleep(3)。

不同信号

实测 · 本机执行输出
信号        进行中的请求                      master 退出(s)  atexit  worker_exit 钩子
SIGTERM   200 done by 7263 (3.02 s)           2.68  1       1
SIGINT    500 (错误页 141 字节) (0.71 s)           0.35  1       1
SIGQUIT   500 (错误页 141 字节) (0.71 s)           0.35  1       1
SIGKILL   200 done by 7268 (3.02 s)           0.01  1       1

graceful_timeout

实测 · 本机执行输出
  进行中的请求 → RemoteDisconnected,1.67 s 后;master 退出 1.08 s
  日志:
    [2026-10-02 15:50:13 +0800] [72714] [INFO] Booting worker with pid: 72714
    [2026-10-02 15:50:13 +0800] [72712] [INFO] Handling signal: term
    [2026-10-02 15:50:14 +0800] [72712] [INFO] Shutting down: Master
  worker 里 atexit: 0 次 | worker_exit 钩子: 0 次(日志里没有 Worker exiting)

SIGHUP 重载

实测 · 本机执行输出
  HUP 之前的 worker pid:2 个;HUP 之后:2 个,与之前重叠 0 个(全部更换)
  进行中的 3 秒请求 → 200 done by 7273,3.0 s;期间 62 次 /pid 请求,失败 0 次;请求中见过的不同 worker pid 数 3
  worker_exit 钩子: 2 次,atexit: 2 次

分步演示

优雅关闭
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。gunicorn(sync worker),macOS
    • 没有验证:gthread/gevent worker 的关闭行为、长连接(keep-alive)与 SSE/WebSocket 的关闭、preload_app 下的 HUP、systemd/Kubernetes 的停止流程与 terminationGracePeriod、SIGUSR2 热升级、worker 超时(--timeout)与关闭的相互作用
    京ICP备2026067502号-1京公网安备11010502063487号