chore(task): 归档 08-10 与 08-11 任务
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{"file":".trellis/spec/backend/market-data-sync.md","reason":"检查并发实现仍满足市场同步完整契约和测试矩阵。"}
|
||||
{"file":".trellis/spec/backend/quality-guidelines.md","reason":"检查 Ruff、Pyright、pytest、禁止模式和集成测试证据。"}
|
||||
{"file":"docs/adr/0004-tushare-six-year-snapshot-sync.md","reason":"检查单股事务/发布顺序、失败隔离和滚动清理没有漂移。"}
|
||||
{"file":".trellis/tasks/08-11-market-sync-concurrency-storage/prd.md","reason":"逐条核对并发、频控、数据库调用数量和兼容性验收条件。"}
|
||||
{"file":".trellis/tasks/08-11-market-data-sync-performance-audit/research/legacy-sync-and-current-bottlenecks.md","reason":"用生产基线和旧实现证据检查性能结论是否被夸大。"}
|
||||
@@ -0,0 +1,43 @@
|
||||
# 八路同步与存储批量化设计
|
||||
|
||||
## 模块接口
|
||||
|
||||
- `SyncMarketData.execute(command)`:外部接口保持不变,内部使用固定大小 executor。
|
||||
- `SyncItemOutcome`:worker 返回值,封装 result/fingerprint/failure;不暴露线程实现。
|
||||
- Tushare 请求协调器:适配器内部接口,执行一个真实 client 方法并隐藏间隔、重试和共享冷却。
|
||||
- `MarketDataRepository.record_items(...)`:批量持久化 outcomes。
|
||||
- `MarketDataRepository.count_valid_stocks(...)`:集合式覆盖率接口。
|
||||
|
||||
## 并发流
|
||||
|
||||
stock master 和 daily_basic 保持主线程顺序执行。bar 阶段把股票提交给最多 8 个 worker;每个 worker
|
||||
完成获取、CSV staging、数据库事务和 CSV 发布后返回。主线程 `as_completed` 聚合并每 100 项刷新
|
||||
审计和日志。批量审计写失败是批次级错误,不回滚已提交事实。
|
||||
|
||||
## Tushare 频控
|
||||
|
||||
由 coordinated client 代理 `pro_bar` 实际调用的 `daily` / `adj_factor`:
|
||||
|
||||
1. 请求前检查共享 cooldown;正常情况下允许最多 8 路并发;
|
||||
2. 调用原始 token client;
|
||||
3. 频控异常扩大共享 cooldown,唤醒/阻塞所有等待 worker;
|
||||
4. 普通临时错误只退避当前调用;
|
||||
5. 到达重试预算后抛出安全 `TushareSourceError`。
|
||||
|
||||
现有可配置请求间隔保留为单股成功后的温和节流,不对所有真实调用强加全局串行间隔。
|
||||
`pro_bar(..., retry_count=1)` 避免 SDK 在看不到共享 gate 的位置自行重试。测试注入 fake clock、wait
|
||||
和 client,不使用真实睡眠或网络。
|
||||
|
||||
## PostgreSQL
|
||||
|
||||
依赖调整为 Psycopg pool extra。CLI 在一次执行期间打开池并在退出时关闭;池最大连接数至少覆盖
|
||||
8 个 worker、一个主线程写连接和 advisory lock 连接。connection 不跨线程共享。
|
||||
|
||||
`record_items` 使用 `executemany` 或 COPY/staging 一次写一批。`count_valid_stocks` 从 active 股票
|
||||
连接/EXISTS 两张目标日事实表后 count,一次返回 valid count。
|
||||
|
||||
## 失败与回退
|
||||
|
||||
- executor 创建或批量审计失败记录 batch 错误并收敛状态。
|
||||
- worker 异常必须转换为 outcome,不能让 future 异常跳过进度。
|
||||
- worker 数可降为 1,得到与原串行流程等价的安全回退。
|
||||
@@ -0,0 +1,5 @@
|
||||
{"file":".trellis/spec/backend/market-data-sync.md","reason":"实施时保持六年 qfq、单股事务、CSV 原子发布、失败重试和覆盖率契约。"}
|
||||
{"file":".trellis/spec/backend/configuration-and-runtime.md","reason":"新增 worker、频控和连接池配置必须通过 Settings 与部署环境传递。"}
|
||||
{"file":"docs/adr/0004-tushare-six-year-snapshot-sync.md","reason":"并发化不得破坏快照比较、事务顺序、partial success 和滚动保留决策。"}
|
||||
{"file":".trellis/tasks/08-11-market-data-sync-performance-audit/research/legacy-sync-and-current-bottlenecks.md","reason":"提供生产基线、旧项目 8 worker/退避模式和当前 Tushare 异常隐藏问题。"}
|
||||
{"file":".trellis/tasks/08-11-market-sync-concurrency-storage/design.md","reason":"定义 worker outcome、请求协调器、连接池和批量仓储接口。"}
|
||||
@@ -0,0 +1,14 @@
|
||||
# 实施计划
|
||||
|
||||
1. 先补失败测试:worker 上限、完成顺序、单股隔离、共享频控和集合覆盖率。
|
||||
2. 在 domain/application 定义 `SyncItemOutcome`,把 `_process_bar` 重构为无共享可变状态的返回式流程。
|
||||
3. 在 Tushare adapter 增加 coordinated client/request coordinator,设置 SDK `retry_count=1`,补错误分类测试。
|
||||
4. 把 `market_data_max_workers` 默认改为 8 并完成正整数校验;CLI 注入同步用例。
|
||||
5. 引入 Psycopg connection pool,保持 advisory lock 与单股事务的独立连接语义。
|
||||
6. 增加 `record_items` 和 `count_valid_stocks`,删除编排中的逐股覆盖率查询。
|
||||
7. 用固定线程池执行 bar futures,主线程聚合、分批审计和记录有界进度。
|
||||
8. 更新 `.env.example`、Compose 参数传递、市场同步文档和依赖锁文件。
|
||||
9. 运行 `uv lock --check`、Ruff format/check、Pyright、pytest;有测试数据库时运行 market_data integration tests。
|
||||
10. 运行 5002 fake 股票无网络基准,记录最大并发、耗时和 repository 调用次数。
|
||||
|
||||
回滚点:连接池改造和并发编排分别保持独立变更;出现供应商问题时配置 worker=1。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 实现八路同步与存储批量化
|
||||
|
||||
## Goal
|
||||
|
||||
在不改变逐股六年 qfq、单股票事务/CSV 发布和覆盖率业务语义的前提下,把行情阶段从串行改为
|
||||
默认 8 路受控并发,并消除 PostgreSQL 连接、审计写入和覆盖率查询的线性额外开销。
|
||||
|
||||
## Dependencies
|
||||
|
||||
- 无子任务依赖;本任务是完整性检查后端的前置任务。
|
||||
|
||||
## Requirements
|
||||
|
||||
- `ZHIXING_MARKET_DATA_MAX_WORKERS` 默认 8,CLI 实际传入同步用例;取值必须大于等于 1。
|
||||
- bar worker 只处理一只股票并返回不可变 outcome,主线程负责计数、进度和批量审计。
|
||||
- 所有 worker 共用 Tushare 请求协调器;真实 `daily` / `adj_factor` 调用能触发共享频控冷却,
|
||||
正常流量不能被一个全局固定间隔重新串行化。
|
||||
- 频控分类至少覆盖旧项目的中文提示、429 和 403;频控冷却默认 60/120/180 秒且可配置。
|
||||
- 普通临时错误有界重试;数据验证错误不重试;所有日志安全且可统计等待时间。
|
||||
- `pro_bar` 继续使用由 `pro_api(token)` 创建的 client,并保留 qfq 计算;内部隐藏重试不得绕开协调器。
|
||||
- PostgreSQL 使用线程安全连接池,每个 worker 借独立连接完成单股票事务。
|
||||
- `market_sync_item` 由主线程分批 upsert;覆盖率由一个集合查询计算。
|
||||
- CLI 参数、退出码、失败重试、advisory lock、滚动清理和摘要字段保持兼容。
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] 并发测试证明默认/配置 worker 上限有效,5002 个 fake 股票不会创建 5002 个线程。
|
||||
- [ ] 不同完成顺序得到相同汇总;单股票失败不影响其他股票,失败股票不发布临时 CSV。
|
||||
- [ ] 一个 worker 命中频控后,其他 worker 在共享冷却截止前不启动新的真实供应商调用。
|
||||
- [ ] `pro_bar` 的 `daily` 与 `adj_factor` 都经过请求协调器,token client 回归测试继续通过。
|
||||
- [ ] PostgreSQL 集成测试覆盖多线程 upsert、事务回滚、批量 item 和集合覆盖率。
|
||||
- [ ] 连接获取次数受池上限约束,覆盖率不再逐股票调用 `has_bar` / `has_daily_basic`。
|
||||
- [ ] 同步用例、CLI 和 Tushare 单元测试通过;后端 Ruff、Pyright、pytest 全部通过。
|
||||
- [ ] 无网络基准记录 5002 股票调度耗时、最大并发和 repository 调用数;生产 30 分钟目标标记为部署后验证。
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- 不改成按交易日增量下载,不持久化 adj_factor。
|
||||
- 不增加 HTTP 或 Web 页面。
|
||||
- 不改变六年窗口、数据表业务字段或选股资格语义。
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "market-sync-concurrency-storage",
|
||||
"name": "market-sync-concurrency-storage",
|
||||
"title": "实现八路同步与存储批量化",
|
||||
"description": "为逐股六年 qfq 同步接入 8 路受控并发、共享频控、连接池、批量审计和集合式覆盖率计算。",
|
||||
"status": "completed",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "yuxuanhui",
|
||||
"assignee": "yuxuanhui",
|
||||
"createdAt": "2026-08-11",
|
||||
"completedAt": "2026-08-11",
|
||||
"branch": null,
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": "08-11-market-data-sync-performance-audit",
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
Reference in New Issue
Block a user