From 83f1546074f0ed88058b8a2e196aec56fec8c34f Mon Sep 17 00:00:00 2001 From: FinDataHub Date: Sat, 19 Sep 2026 23:10:38 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=AE=B0=E5=BD=95=20stuck=20=E8=AF=AF?= =?UTF-8?q?=E6=8A=A5=E6=A0=B9=E5=9B=A0=E4=B8=8E=E6=9C=AC=E6=89=B9=EF=BC=88?= =?UTF-8?q?3/4/5=20=E9=A1=B9=EF=BC=89=E4=BA=A4=E4=BB=98=E6=B1=87=E6=80=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 清单:新增 P0 章节(stuck 误报机制 + 6 条用例 + 撞锁守卫), 并补本批交付汇总表(含 5c 凭据轮换仍须外部操作) - 记忆:stuck 误判 → 自动重启的完整机制与修法;E2E 与采集器撞锁 --- .workbuddy/memory/2026-09-18.md | 36 +++++++++++++++ FinDataHub-未解决问题清单-2026-09-17.md | 61 +++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/.workbuddy/memory/2026-09-18.md b/.workbuddy/memory/2026-09-18.md index 9ab604e..3bf1c99 100644 --- a/.workbuddy/memory/2026-09-18.md +++ b/.workbuddy/memory/2026-09-18.md @@ -497,3 +497,39 @@ shebang / .pth。**`--check` 可作启动自检或 CI 门禁。** ### 新增可复用工具(本批) `relocate_bundle_venvs.py`(venv 自包含,check 可作 CI 门禁)、 `verify_fulltext_equivalence.py`(全文检索 vs LIKE 等价性对照)。 + + +--- + +## 第十批(23:00–23:30):`stuck` 误报导致采集器被反复自动重启(根因) + +### 机制(「一天被判定异常停止 193 次」的根因) +- `get_status()` 用「DB 最后写入 > **300s**」判 `stuck` +- 非交易时段节能模式:间隔 30s → **3600s**,**期间刻意不写数据** + → 每个非交易小时约 55 分钟被误判 +- `AutoRecoveryManager.swift:166`:`if st.stuck == true { return .collectorStuck }` + → **触发自动重启采集器** +- 实证:20:27 / 20:46 / 21:05 / 21:24 / 21:49 / 22:11 规律性停止 + +### 修法 +`stuck` 改看**心跳**(心跳线程每 60s 刷新、长休眠也活跃;Swift 免 spawn 探测本就 +读心跳,本次统一 CLI 路径)。回退阈值 **4200s**(> 节能上限 3600s + 余量)。 +**无写入时间可比时保守判不卡死**(空库/DB 异常不触发重启)。 +`last_write_time` 语义不变。 +顺带修:DB 返回 datetime 对象时 `str()` 带微秒 → `strptime` 抛 +`unconverted data remains`;新增 `_parse_ts()` 容错。 +新增 6 条用例,5 条旧契约用例同步更新。Scripts/bin 214 → **220**。 + +### 附带:E2E 用例与采集器撞锁 +`test_unified_writer_e2e` 真写 `news_unified` → `(1205, Lock wait timeout)`。 +它此前"通过"只因采集器当时停摆 13 小时,**修好采集后反而暴露**。 +已加守卫:采集器活跃时 skip 并说明。kuaixun 54s → **3.9s**。 + +### 本批交付(第 3/4/5 项) +- 3a P1-11:**否决**(ngram 与 LIKE 不等价) +- 3b P2-19:`NewsFlashService.swift` 1054→821 + 3 extension(编译验证) +- 3c P2-20:client 建 venv + 38 测试 + **修 SQL 注入** + 登记 CI +- 4:三表增量路径已验证(opt_daily 1049 万行 14s) +- 5a/5b:venv 内联自包含(59M)+ 补打包 `common/` +- 5c:凭据轮换须外部操作(Tushare 后台 / MySQL 口令 + 7 个 plist) +**测试合计 1147 passed。** diff --git a/FinDataHub-未解决问题清单-2026-09-17.md b/FinDataHub-未解决问题清单-2026-09-17.md index e559fd2..b213ce7 100644 --- a/FinDataHub-未解决问题清单-2026-09-17.md +++ b/FinDataHub-未解决问题清单-2026-09-17.md @@ -1023,3 +1023,64 @@ kuaixun 因可能依赖本机服务单列为非阻塞。 `PythonProcessManager.swift`(842)、`DatabaseSetupGuideView.swift`(807) 等。 这些文件承载数据采集与进程管理的核心逻辑,拆分需逐文件评估依赖并逐一编译验证, 不适合批量机械处理。 + + +--- + +## 新增 P0:`stuck` 误报导致采集器被反复自动重启(2026-09-19 23:20 修复) + +### 机制(这是「一天被判定异常停止 193 次」的根因) +`get_status()` 用「数据库最后写入距今 > **300s**」判定 `stuck`; +而非交易时段采集器进入节能模式,采集间隔由 30s 退避到 **3600s** +(日志 `[eco] 非交易时段,采集间隔 30s → 3600s`)、**期间刻意不写数据** +→ 每个非交易小时里约 **55 分钟**被误判为卡死。 + +同时 `AutoRecoveryManager.swift:166`: +```swift +if st.stuck == true { return .collectorStuck } +``` +即 `stuck` 被当作可恢复故障 → **自动重启采集器**。 + +实证时间线(今日 debug.log):20:27 / 20:46 / 21:05 / 21:24 / 21:49 / 22:11 +呈规律性停止,间隔与健康检查周期一致。 + +### 修法 +`stuck` 改由**心跳**判定(心跳线程每 60s 刷新、长休眠时也活跃;Swift 侧的免 spawn +探测本就是读心跳的,本次把 CLI 路径与之统一): +- 心跳新鲜(≤3×60s)→ 不卡死 +- 心跳过期/缺失 → 回退判定,阈值取 **4200s**(>节能上限 3600s + 余量) +- **无写入时间可比时(空库 / DB 读取异常)保守判为不卡死** —— + `stuck` 会触发自动重启,误判代价高于漏判 +- `last_write_time` 语义不变,仍如实反映数据写入 + +顺带修解析脆弱性:DB 返回 `datetime` 对象时 `str()` 带微秒, +原 `strptime("%Y-%m-%d %H:%M:%S")` 抛 `unconverted data remains: .219352`; +新增 `_parse_ts()` 容错。 + +### 验证 +新增 6 条用例(核心回归:**节能空闲 1 小时但心跳鲜活 → 不得判 stuck**, +旧逻辑必判 true);5 条旧契约用例同步更新。部署位实测 +`{"stuck": false}` 而 `last_write_time` 仍为 26 分钟前 —— 语义正确。 + +### 附带:kuaixun E2E 与采集器撞锁 +`test_unified_writer_e2e` 真实写 `news_unified`,与在跑的采集器撞锁: +`(1205, 'Lock wait timeout exceeded')`。它此前"通过"只因采集器当时停摆 13 小时 —— +**修好采集后反而暴露**。已加守卫:采集器心跳活跃时 `pytest.skip` 并说明原因, +而非任其随机失败。kuaixun 耗时 54s → **3.9s**。 + +--- + +## 本批(第 3/4/5 项)交付汇总 + +| 项 | 结果 | +|---|---| +| **3a** P1-11 搜索提速 | ✅ 已评估并**否决**(实测 ngram 与 LIKE 不等价,会静默丢结果) | +| **3b** P2-19 超大文件拆分 | ✅ 首批:`NewsFlashService.swift` 1054→821 + 3 个 extension(编译验证) | +| **3c** P2-20 client | ✅ 建 venv + 38 条测试 + **修复 SQL 注入** + 登记 CI | +| **4** 三表参数接线 | ✅ 已验证增量路径正确(`opt_daily` 1049 万行 14s 完成增量) | +| **5a** venv 软链接脆弱 | ✅ 已修:运行时内联(裁至 59M)+ 修 shebang/.pth,`--check` 可作门禁 | +| **5b** 打包漏 `common/` | ✅ 已修(并更正:桌面后端不导入 `app/main.py`,**未**造成当前故障) | +| **5c** 凭据轮换 | ⬜ **须外部操作**:Tushare token 需在 tushare.pro 后台重置;MySQL 口令轮换需同步改 env 文件 + 7 个 launchd plist,属运维窗口动作 | + +**测试总量:1147 passed**(core 122 / client 38 / tushare 174 / akshare 183 / +Scripts 220 / kuaixun 410)。