问题描述
部署后访问 Web 页面非常慢,首次加载需要等待数分钟,健康检查频繁超时(unhealthy)。
根因分析
Dockerfile 中 gunicorn 启动命令硬编码为:
CMD ["gunicorn", "-w", "1", "-b", "0.0.0.0:5000", "--timeout", "120", "--access-logfile", "-", "web_outlook_app:app"]
-w 1 + sync worker 意味着所有请求串行处理,一次只能响应一个请求。
并发竞争
以下请求源同时竞争唯一的 worker:
| 来源 |
频率/数量 |
| APScheduler 后台任务(通知分发、API 探测、邮箱池维护、Token 刷新) |
持续运行,API 探测每 5 秒一次 |
Docker 健康检查 (/healthz) |
每 30 秒 |
| 用户浏览器请求(HTML + CSS + JS) |
每次页面加载多个请求 |
| iOS Safari 预加载(apple-touch-icon 等) |
自动触发 |
| 社交媒体爬虫(Facebook/Twitter) |
不定时 |
当后台任务占用 worker 时,用户请求排队等待,导致页面加载需要数分钟。
实际日志证据
健康检查连续超时(5 次 FailingStreak),/healthz 请求在 4 秒超时内无法得到响应:
同时静态文件(CSS/JS)返回 200 但 body 为 0 字节:
"GET /static/css/main.css HTTP/1.1" 200 0
"GET /static/js/i18n.js HTTP/1.1" 200 0
建议方案
理解 -w 1 是为了避免 APScheduler 多进程冲突和 Flask 内存 session 不同步问题,但 sync worker 严重影响了生产环境可用性。
方案 A:改用 gevent worker(推荐,改动最小)
CMD ["gunicorn", "-w", "1", "-k", "gevent", "-b", "0.0.0.0:5000", "--timeout", "120", "--access-logfile", "-", "web_outlook_app:app"]
单 worker + gevent 可以并发处理多个请求(协程),不创建多进程,不影响 APScheduler 和 session。只需在 requirements.txt 中添加 gevent。
方案 B:拆分调度器到独立进程
将 APScheduler 运行在独立的进程/线程中,Web 部分可以安全地增加 worker 数量。改动较大但架构更清晰。
方案 C:支持环境变量覆盖
允许通过环境变量(如 GUNICORN_WORKERS、GUNICORN_WORKER_CLASS)覆盖启动参数,让用户根据部署场景自行调整。
环境信息
- 镜像:
ghcr.io/zeropointsix/outlook-email-plus:latest
- 容器资源:CPU 0.01%,MEM 65MiB(资源充足,非性能瓶颈)
- 客户端:macOS Chrome / iOS Safari
问题描述
部署后访问 Web 页面非常慢,首次加载需要等待数分钟,健康检查频繁超时(unhealthy)。
根因分析
Dockerfile 中 gunicorn 启动命令硬编码为:
-w 1+ sync worker 意味着所有请求串行处理,一次只能响应一个请求。并发竞争
以下请求源同时竞争唯一的 worker:
/healthz)当后台任务占用 worker 时,用户请求排队等待,导致页面加载需要数分钟。
实际日志证据
健康检查连续超时(5 次 FailingStreak),
/healthz请求在 4 秒超时内无法得到响应:同时静态文件(CSS/JS)返回 200 但 body 为 0 字节:
建议方案
理解
-w 1是为了避免 APScheduler 多进程冲突和 Flask 内存 session 不同步问题,但 sync worker 严重影响了生产环境可用性。方案 A:改用 gevent worker(推荐,改动最小)
单 worker + gevent 可以并发处理多个请求(协程),不创建多进程,不影响 APScheduler 和 session。只需在 requirements.txt 中添加
gevent。方案 B:拆分调度器到独立进程
将 APScheduler 运行在独立的进程/线程中,Web 部分可以安全地增加 worker 数量。改动较大但架构更清晰。
方案 C:支持环境变量覆盖
允许通过环境变量(如
GUNICORN_WORKERS、GUNICORN_WORKER_CLASS)覆盖启动参数,让用户根据部署场景自行调整。环境信息
ghcr.io/zeropointsix/outlook-email-plus:latest