295177027f
work #01 (2026-07-03):昨天 15:30 runall 中 kline_5min 全量 69min 把 2h 窗口吃满,share_snapshot / market_regime 被 systemd SIGTERM 截断; 今天又叠加 worker.py 未长驻,导致 10 个 task missed。 变更: - bin/systemd/market-sync.service: TimeoutStartSec 7200 → 14400 (4h) - bin/daily_sync_check.py: 新增每日巡检,读 PG dataset_registry, 对比 SCHEDULE 判定 ok/missed/failed/stuck/never_run,写 JSON 报告, 失败时 POST HMAC webhook - bin/systemd/market-sync-daily-check.{service,timer}: 23:00 daily 触发 daily_check(替代 session-only 的 /loop 方案) - config/daily_check_secrets.env.template: webhook 配置模板 - docs/works/2026-07-03-01-market-sync-timeout.md: 完整 work 记录 (根因 + 中期/长期改进建议) Co-Authored-By: Claude <noreply@anthropic.com>
3.3 KiB
3.3 KiB
2026-07-03 — work #01: market-sync.service 2h timeout 截断同步
发现
跑 bin/daily_sync_check.py --report-only(周五 10:31)→ 10 个 missed:
❌ stock_basic / kline_daily / kline_index / kline_5min / tick_trade
❌ moneyflow / industry_sector / sector_features / market_regime / longhubang
✅ share_snapshot (今日 00:03:01 手动跑过)
⏸ stock_node (周末专属任务,今天周五不期望)
根因
不是今天调度出问题,是昨天 2026-07-02 15:30 runall 没跑完:
15:30:01 启动 runall
15:38:50 stock_basic 完成 (529s)
15:38:58 kline_index 完成 (2s)
15:56:54 kline_daily 完成 (1072s) warning
17:06:09 kline_5min 完成 (4150s=69min) ← 单 task 吃掉一半窗口
17:22:37 industry_sector 完成 (983s) warning (baostock timeout)
17:24:27 sector_features 完成 (105s)
17:24:32 >>> 开始 share_snapshot
17:30:01 systemd SIGTERM 杀进程 ← TimeoutStartSec=7200 (2h) 到期
✗ share_snapshot 没跑
✗ market_regime 没跑
后果链:
- 昨天 kline_5min 全量同步 5207 只耗时 69 min(4150s),单 task 吃掉 1/2 窗口
- industry_sector 又因 baostock connection timed out 浪费 16 min
- 17:30 systemd timeout 砍掉 share_snapshot + market_regime
- 今天 09:00 该跑的 stock_basic 没跑 —— 因为 worker.py 没长驻 + market-sync.timer 只在 15:30 触发
- tick/moneyflow/lhb 几个独立 timer 在 21:05/21:35/22:00 跑过但今天又没补
解决
短期(本次 commit)
bin/systemd/market-sync.service:TimeoutStartSec从7200(2h) 提到14400(4h)- 注释
实际 ~80min→ 改成~80min + kline_5min 增量 70min, 总 ~2.5h, 留 buffer
- 注释
- 加
bin/systemd/market-sync-daily-check.timer+.service- 每天 23:00 跑
bin/daily_sync_check.py,替代/loop方案的 session-only 限制
- 每天 23:00 跑
中期(不在本次 commit,记录备查)
- kline_5min 改成增量模式(当前是全量 5207 只每次),预计从 69min 降到 5min
- 增量条件:
bar_time >= 上次同步时间 - 1 天(含补漏)
- 增量条件:
- worker.py 长驻 + 进程内 scheduler 接管盘后 task 调度,与 systemd timer 二选一(dual-scheduler-overlap)
- 失败 task 自动 retry 一次(仅 failed,不 retry partial-success / warning)
长期(架构改进)
- runall 拆成 fast-path / slow-path 两个 service:
- fast-path: stock_basic / kline_index / kline_daily / industry_sector / share_snapshot / market_regime(~30min)
- slow-path: kline_5min 全量(独立 timer @ 周日凌晨,避免挤占交易日窗口)
关联
- background-watcher-pitfalls: "不要让 systemd TimeoutStartSec= 自动收尾"
- 实际情况是 runall 卡在 kline_5min,wrapper 的 fast-poll 也没起到作用(runall 在 2h 内确实没退出,systemd 超时是对的)
- dual-scheduler-overlap: worker.py 没运行 → 完全依赖 systemd timer
- market-data-overview: 任务耗时分布
验收
commit 后验证:
sudo cp bin/systemd/market-sync.service /etc/systemd/system/
sudo cp bin/systemd/market-sync-daily-check.{service,timer} /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl restart market-sync.timer
systemctl status market-sync-daily-check.timer
# 等今晚 23:00 看 daily_check 报告