Python 服务稳定性加固(进程 / 会话 / 并发)
Overview
把"长期运行的 Python 服务(行情拉取、波动率预计算、看门狗)"最常见的三类事故,沉淀为可复用的加固模板:
1. request 会话复用:Windows 下每次 requests.Session() 重新加载 SSL 证书耗时 3s+;全局复用把 11.7s 降到 2s。
2. 外部脚本调用绝不 fire-and-forget:Popen 后台调用若脚本卡死,会被周期任务无限堆积 → 吃满内存拖垮整机。改用 subprocess.run(timeout=) 同步+超时 + "正在运行"状态防重入锁。
3. 并发兜底:遍历大量文件 / 网络 IO 时用 ThreadPoolExecutor 并发,但必须加主线程收集超时 + 全局 os._exit 硬兜底,确保任何情况都绝不无限卡死。
When To Use
- 用户说"服务卡死 / 进不去 / 内存被吃满"
- 用户要写"看门狗 / 定时任务 / 周期刷新"调用外部脚本
- 用户抱怨"requests 调用很慢 / Windows 下 HTTPS 慢"
- 用户要做"并发拉取 / 批量解析"且担心个别任务卡死拖垮整体
Three hard rules
- 会话复用:进程内只建一个
requests.Session(),所有请求走它(见scripts/session_reuse.py)。 - 同步等待 + 超时 + 防重入:调用外部脚本用
subprocess.run([...], timeout=T),不要用Popen不等待;用状态锁标记"正在运行"防止周期任务重复 spawn(见scripts/safe_subprocess.py)。 - 并发有上限 + 全局兜底:
ThreadPoolExecutor(max_workers=N)并发,主线程设收集超时,threading.Timer到点os._exit,绝不等待残留 worker(见scripts/concurrent_with_timeout.py)。
Workflow
- 定位瓶颈:用
scripts/session_reuse.py的基准对比确认是否 SSL 重复加载拖慢。 - 替换 fire-and-forget:用
scripts/safe_subprocess.py改写所有周期任务的外部脚本调用。 - 加固批量 IO:用
scripts/concurrent_with_timeout.py改写大批量遍历 / 并发拉取。 - 复盘检查:按
references/postmortem.md的清单逐项核对。
Resources
scripts/session_reuse.py— 全局 Session 复用 + 基准对比,可运行scripts/safe_subprocess.py— subprocess.run(timeout) + 防重入锁,可运行scripts/concurrent_with_timeout.py— ThreadPoolExecutor + 收集超时 + os._exit 兜底,可运行references/postmortem.md— 真实事故复盘 + 检查清单