From 14d3531f779ec839918f637f8c0329e00469f093 Mon Sep 17 00:00:00 2001 From: claude_dev Date: Sun, 6 Sep 2026 19:45:18 +0800 Subject: [PATCH] =?UTF-8?q?docs(data):=20=E8=AF=AD=E6=96=99=E5=BA=93spec?= =?UTF-8?q?=C2=A718=E4=BF=AE=E8=AE=A2=E2=80=94=E2=80=94=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=B8=A4=E6=9D=A1=E5=8F=8D=E9=A6=88=E8=90=BD=E5=9C=B0=20[nas]?= =?UTF-8?q?=E2=80=94=E2=80=94=E2=91=A0=E6=96=AD=E7=82=B9=E7=BB=AD=E4=BC=A0?= =?UTF-8?q?=E9=92=A6=E7=82=B9=E5=8A=A0=E5=9B=BA:unit=E7=B2=92=E5=BA=A6mark?= =?UTF-8?q?er+=E5=8E=9F=E5=AD=90=E5=86=99+=E6=9D=80=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E9=87=8D=E5=90=AF=E5=8D=B3=E4=BB=8E=E6=9C=AA=E5=AE=8C=E6=88=90?= =?UTF-8?q?unit=E7=BB=AD=E8=B7=91+=E6=BC=8F=E6=97=A5=E8=87=AA=E6=84=88(?= =?UTF-8?q?=E5=85=AC=E5=91=8AT-1~T=E4=B8=A4=E5=A4=A9=E7=AA=97/=E6=96=B0?= =?UTF-8?q?=E9=97=BBrecent-100=E5=A4=A9=E7=84=B6=E8=A6=86=E7=9B=96?= =?UTF-8?q?=E6=95=B0=E6=97=A5=E7=BC=BA=E5=8F=A3)+daily=E5=B9=82=E7=AD=89?= =?UTF-8?q?=E5=8F=AF=E9=87=8D=E8=B7=91,=E9=AA=8C=E6=94=B6=E5=8A=A05b?= =?UTF-8?q?=E6=9D=A1(kill=20-9=E9=87=8D=E5=90=AF=E7=BB=AD=E8=B7=91?= =?UTF-8?q?=E5=AE=9E=E8=AF=81);=E2=91=A1=E8=A7=A3=E7=BB=91docker(=E7=94=A8?= =?UTF-8?q?=E6=88=B7:=E3=80=8C=E4=B8=8D=E8=A6=81=E5=92=8Cdocker=E7=BB=91?= =?UTF-8?q?=E5=AE=9A,=E9=81=BF=E5=85=8Ddocker=E9=87=8D=E5=90=AF=E5=B0=B1?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E3=80=8D):=E9=87=87=E9=9B=86=E8=BF=9B?= =?UTF-8?q?=E7=A8=8B=E6=94=B9NAS=E5=AE=BF=E4=B8=BB=E6=9C=BA=E7=9B=B4?= =?UTF-8?q?=E8=B7=91,=E8=BF=90=E8=A1=8C=E6=97=B6=3D/volume1/stock/corpus/v?= =?UTF-8?q?env(--copies=E8=87=AA=E4=B8=BE,DSM=E8=87=AA=E5=B8=A6Python3.8.1?= =?UTF-8?q?2+pip=E5=AE=9E=E6=B5=8B=E5=8F=AF=E7=94=A8x86=5F64,=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E9=94=81cp38=E7=89=88),=E5=AE=B9=E5=99=A8=E9=87=8D?= =?UTF-8?q?=E5=90=AF/=E5=8D=87=E7=BA=A7/=E5=81=9C=E7=94=A8=E9=9B=B6?= =?UTF-8?q?=E5=BD=B1=E5=93=8D;=E5=85=88=E4=BE=8B=3D=E7=8E=B0=E6=9C=89DSM?= =?UTF-8?q?=2003:00=E5=90=8C=E6=AD=A5=E9=93=BE(id=3D2,crontab=E5=AE=9E?= =?UTF-8?q?=E8=AF=817=E6=9D=A1=E4=BB=BB=E5=8A=A1=E5=9C=A8=E8=B7=91)?= =?UTF-8?q?=E5=AE=BF=E4=B8=BB=E6=9C=BA=E7=9B=B4=E8=B7=91=E5=A4=9A=E5=B9=B4?= =?UTF-8?q?=E9=9B=B6docker,=E6=9C=AC=E8=AE=BE=E8=AE=A1=E6=B2=BF=E5=90=8C?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E6=94=B9admin=E8=B7=91=E9=81=BFroot=E5=B1=9E?= =?UTF-8?q?=E4=B8=BB=E5=9D=91;=E9=AA=8C=E6=94=B6=E5=8A=A0docker=E5=85=A8?= =?UTF-8?q?=E5=81=9C=E4=B8=8B=E7=85=A7=E8=B7=91=E5=AE=9E=E8=AF=81;T1?= =?UTF-8?q?=E6=94=B9venv=E8=87=AA=E4=B8=BE=20[nas]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2026-07-21-data-source-fusion-design.md | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/docs/superpowers/specs/2026-07-21-data-source-fusion-design.md b/docs/superpowers/specs/2026-07-21-data-source-fusion-design.md index 79b1eb6..ae3c077 100644 --- a/docs/superpowers/specs/2026-07-21-data-source-fusion-design.md +++ b/docs/superpowers/specs/2026-07-21-data-source-fusion-design.md @@ -414,11 +414,14 @@ FETCHERS 注册表新增两键即自动可被未来 provider MCP server 暴露 1. **存储全部落 NAS、一律不上 VPS**——「vps承载有压力,之前基本面都放在了nas上,没有放vps,本次 也一样」。VPS 零参与:零 schtask、零存储、零采集进程;repo 里进脚本仅为随 NAS 部署管道分发 - (promote --target nas → /app),VPS 侧永远不会被调度。 -2. **采集发起位置=NAS 本机**(sanguo_vnpy_v2 容器内 docker exec)。关键差异:家宽出口 IP ≠ VPS - 公网 IP(49.232.102.198),与 VPS 侧 ak-daily/ak-events 的东财限流**零冲突**——这正是采集放 - NAS 的第二个理由(第一个是存储)。09-06 实测佐证:np-listapi/巨潮/东财文章页 ~35 发连续探测 - 自家宽 IP 全成功、零限流。 + (promote --target nas → /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2/,**宿主机 + 直读该路径,不经容器**),VPS 侧永远不会被调度。 +2. **采集进程=NAS 宿主机直跑,不绑定 docker**(用户钦点:「不要和docker绑定,避免docker重启就 + 失败」)。运行时=/volume1/stock/corpus/venv(`python3 -m venv --copies` 自举,DSM 自带 + Python 3.8.12/pip 已实测可用,x86_64;依赖锁 cp38 兼容版 pandas/pyarrow/requests)——容器 + 重启/升级/停用零影响,venv `--copies` 连 DSM 换 Python 也不怕。家宽出口 IP ≠ VPS 公网 IP + (49.232.102.198),与 VPS 侧 ak-daily/ak-events 的东财限流**零冲突**。09-06 实测佐证: + np-listapi/巨潮/东财文章页 ~35 发连续探测自家宽 IP 全成功、零限流。 3. **时间带**:全部采集限于 **00:30–17:30**,避开 18:05–23:45 傍晚带(VPS 夜任务密集+家宽使用)。 唯一日窗=每日 06:00 起(见 18.3)。 4. 慢爬纪律:单进程单线程、per-domain 限速+抖动、直连不走代理(Session.trust_env=False,防 @@ -457,11 +460,21 @@ Schema(列名冻结,消费方=factor session 因子加工层,后续 provider fet - **脚本**: `scripts/data_platform/corpus_download.py`(repo 内唯一新文件;单脚本红线同款—— corpus 栈一个入口,类型靠内部注册表,禁再开新脚本)。参数 `--lane daily|backfill`、 `--until HH:MM`(墙钟自停)、`--limit N`(手动冒烟)。 -- **调度**: DSM 任务计划 **sanguo-corpus-daily,每日 06:00 一条**: - `docker exec sanguo_vnpy_v2 python -X utf8 /app/scripts/data_platform/corpus_download.py - --lane daily && docker exec … --lane backfill --until 17:30` - (两 lane 串行同进程域=天然互斥;rc 聚合,任一 lane 失败 log 留痕)。回补 lane 每日从断点续跑, - 17:30 前完成当前 unit 即 checkpoint 退出。 +- **调度**: DSM 任务计划 **sanguo-corpus-daily,每日 06:00 一条,以 admin 身份跑**(先例=现有 + 03:00 同步链 DSM 任务(id=2),宿主机直跑多年零 docker;本设计沿同模式但改 admin 跑,避该链 + root 属主文件坑): + `/volume1/stock/corpus/venv/bin/python -X utf8 + /volume1/homes/admin/.sanguo_projects/sanguo_vnpy_v2/scripts/data_platform/corpus_download.py + --lane daily && 同解释器 --lane backfill --until 17:30` + (两 lane 串行=天然互斥;rc 聚合,任一 lane 失败 log 留痕)。**全程零 docker 依赖**。 + +**断点续传(用户钦点加固,所有 lane 的第一设计原则)**: +- 粒度=unit(公告=(stock,year)/新闻=(stock,page)/全文/PDF=单 id),每 unit 一枚 marker(state/ + 下原子写 tmp+rename);进程被杀/断电/重启后,重启即从「未标 done 的最老 unit」续跑,**无任何 + 全局重启语义**;17:30 墙钟=完成当前 unit 即 checkpoint 退出,次日 06:00 自动接续。 +- daily lane 幂等可重跑(短窗 id 去重,重复执行零副作用);漏日自愈=公告 T-1~T 两天窗,新闻 + recent-100 页面天然覆盖数日缺口(冷门股 100 条跨数月)——某天整个任务没跑,次日一次执行即可 + 补齐,不依赖专门回补。 **daily lane(每日,总 ~4.5h,06:00–10:30 前后)**: 1. 公告增量(巨潮,~5400 req @1/s≈1.5h):每股 seDate=T-1~T 两天窗+`announcement_id` 短窗去重 @@ -508,7 +521,10 @@ PDF 按可得性实下(404 标 missing 不重试);每源每股记录 first_date 3. **news 回补**: 600519 最早条目落 2023-09±1 月(实测硬顶对齐);depth_summary.json 全量产出。 4. **PDF**: 抽 20 份跨年份可打开(%PDF 魔数+size>0+meta 可反查路径);索引行数=文件数。 5. **边界**: /volume1/stock/corpus 之外零写入;VPS 零改动(git diff 触及面仅 scripts+tests+docs); - 容量闸门演练一次(临时阈值)证明会停。 + 容量闸门演练一次(临时阈值)证明会停;**docker 全停状态下手动触发 corpus-daily 照跑通** + (不绑容器的验收实证)。 +5b. **断点续传**: 回补中途 `kill -9` 采集进程→重启后从未完成 unit 续跑,已完成 unit 零重拉 + (marker 核对);某日整个任务停跑一天→次日单次执行把漏日补齐(T-1~T 窗+recent-100 覆盖)。 6. **测试**: tests/data_platform/ 新增 CI 测试(fetch 全 mock 零网络)——失败语义/短窗去重/ 两天窗自愈/墙钟自停/unit marker,全套本地绿+CI 绿。 @@ -520,9 +536,10 @@ parquet);月度 compaction(数据量小,YAGNI)。 ### 18.7 实施步骤概要(验收通过后,TDD) -T1 连通金丝雀(容器内 1 发/域+目录骨架)→ T2 corpus_download.py daily lane 四段+state 机制 -+测试 → T3 DSM 任务注册+首周人工盯跑 → T4 backfill lane ①② → T5 ③④+容量闸门 → T6 验收 -清单执行+活文档本节补「实施终态」小节。每步一个 commit,标签 **[nas]**(VPS 零触及)。 +T1 宿主机 venv 自举(`--copies`,锁 cp38 兼容版本 pandas/pyarrow/requests,清华镜像)+连通金丝雀 +(每域 1 发)+目录骨架 → T2 corpus_download.py daily lane 四段+断点续传 state 机制+测试 → +T3 DSM 任务注册(admin 身份,零 docker)+首周人工盯跑 → T4 backfill lane ①② → T5 ③④+容量闸门 +→ T6 验收清单执行+活文档本节补「实施终态」小节。每步一个 commit,标签 **[nas]**(VPS 零触及)。 ## 参考(调查来源)