台账 056:计划接口超时复发的根因与修法,并写明这仍是补丁

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
zlt 2026-09-10 09:15:58 +08:00
parent 47369d3e58
commit d631a31ebb
1 changed files with 16 additions and 0 deletions

View File

@ -511,3 +511,19 @@
- **修法。** 给实时计划接口加进程内缓存:键是真实数据日加三个装配参数(不传日期时先取最新数据日作键,明早换日立刻失效,不等过期),过期时间环境变量 PLAN_CACHE_SEC 默认六百秒nocache=1 强制重算,重新生成计划时整体清空,最多留八份防内存慢涨。区制段与市场段仍在缓存之外实时读,所以 08:45 追加的当日区制不会被缓存住。同一数据日的装配结果本来就是确定的(用的全是昨收与昨夜数据),缓存安全。
- **读数。** 重启后首次三十一点六秒、第二次零点八六秒、第三次一点零秒PMS 侧拉计划从三十三秒降到二点九秒,强制刷新零点八秒,候选与状态都是零秒。
- **留下的两件事。** 一,每早 07:10 生成新计划后第一次拉仍要三十多秒缓存按数据日失效PMS 08:40 那次会等这一下,六十秒超时够用;要更稳可在盘前链末尾加一次预热调用。二,装配本身该瘦身:读因果论断二十秒是大头,值得单独优化,但那要动取数口径,另开一次。
## 056 · 2026-09-10 · 计划接口超时复发:缓存存活拉长到整个交易日,并让同一个键只算一次
- **故障。** 09-10 开盘前 09:02用户打开 PMS 页面又报「上游的选股计划读不到 · timeout of 60000ms exceeded」另一条是 `/api/open-scan` 同样超时。台账 054 那次的缓存已经上线并生效,但故障复发了。
- **根因,两半。** 第一半是缓存只活十分钟。PMS 的盘前拉计划在 08:40 跑过一次,那次花了三十九秒、把缓存打热,但它在 08:50 就过期了;用户 09:02 打开页面时缓存已经空了二十二分钟,正好撞上冷启动。第二半更要命:装配那一句写在锁外面,页面一次加载并发拉好几路,全部判缓存未命中、各自跑一趟三十多秒的装配、还互相抢同一批数据库连接,实际耗时远超单跑一次——这才是压过六十秒的直接原因。台账 054 只解决了「同一天内重复请求」,没解决「每天第一次」和「并发同时进来」这两种情形。
- **修法。** 两条。一,缓存存活时间从十分钟改成十二小时。这不是为了省算力:缓存键里带的是真实数据日,上游换日后旧那份立刻失效,新鲜度本来就不靠时间保;十二小时是为了让 08:40 那次预热管得到收盘。二,同一个键同时只算一次。第一个请求去算,后到的等它算完直接吃缓存;不同参数组合各有各的锁,互不阻塞。
- **验证读数。** 实机三路并发打同一个没用过的参数键,三路都在三十四秒左右返回、总墙钟三十四秒,等于单跑一次的耗时;修复前会是三路各跑一遍。离线自检 test_plan_cache.py 钉住四件事:换日立刻失效、同键只算一次、不同参数不互相阻塞、存活时间盖得住交易日。
- **要说清的一件事:这仍然是补丁,不是解法。** 三十三秒的装配一直都在,缓存只是把「每次都三十三秒」变成「每天第一次三十三秒」。任何让缓存失效的事——重启、换日、换参数、过期——都会把它重新暴露出来,今天这次就是。正解是把装配挪到盘前算好、落一份结果,接口只做一次查询。另外现在每种参数组合各算一遍也是浪费:不同的 top 与 obs_top 装配的是同一批数据,只是返回条数不同,本该算全量存一份、读的时候截取。这两件事另开一次拍板,见 057。
- **预期。** 交易日内计划接口不再出现超时;每天只在盘前预热那一次花三十多秒。
- **复核日期。** 连续三个交易日观察 PMS 页面有没有再报超时。