bigywater.tech
Flask · 146

后台线程与 Application Context

在视图里起一个线程做后台工作,要注意什么?为什么读不到 current_app?线程里出错了谁知道?重启服务时线程里的任务会怎样?这篇用真实的 gunicorn 与 SIGTERM 把每个问题量出来。

RuntimeError
新线程里访问 current_app 或 db.session 的结果
0.3 / 2.4 秒
SIGTERM 之后 master 退出的时间:daemon 线程与非 daemon 线程
日志里
后台线程抛出的异常出现的位置,不经过 errorhandler

没有上下文的线程

实测 · 本机执行输出
  current_app.name       → RuntimeError: Working outside of application context.
  db.session.execute     → RuntimeError: Working outside of application context.

上一篇:多进程下的全局变量;下一篇:请求超时。

推入应用上下文

实测 · 本机执行输出
  current_app.name       → bg
  query                  → 1
  has_app_context        → True
  session_id             → 4439028624
  after_exit             → False
  线程里的 db.session 与请求线程里的是不是同一个: False (各有各的 session)
  (传给线程的是真实的 Flask 对象 current_app._get_current_object(),不是代理)

线程里的异常

实测 · 本机执行输出
  POST /fail → 200 {"ok":true}
  响应是 200;异常出现在服务器日志里: True | 日志片段: ['Exception in thread Thread-1 (failing):']

停止 worker 时的线程

实测 · 本机执行输出
  daemon     线程:master 在 SIGTERM 后 0.3 秒退出,任务是否做完:False
  nondaemon  线程:master 在 SIGTERM 后 2.4 秒退出,任务是否做完:True

用 gunicorn gthread worker,SIGTERM 发给 master 进程,--graceful-timeout 设为 10 秒。

分步演示

后台线程与 Application Context
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动。Flask-SQLAlchemy 3.1.1、gunicorn gthread
    • 没有验证:Celery 等任务队列的上下文处理、线程池 ThreadPoolExecutor 的行为、--max-requests 回收 worker 时的线程、超过 graceful-timeout 后被强杀的表现、数据库连接在线程结束时的归还
    京ICP备2026067502号-1京公网安备11010502063487号