feat(gateway): 定时下派通道——周期性盘点账号订单并回写网关编目
新增 §12 定时下派通道:网关自己定期派 order_list / order_detail 查询,把账号
真实订单沉淀进新表 account_orders(回写网关),上游可直接查 GET /api/account/orders
拿到账号里实际有哪些订单,不必自己记 order_number。
- collector.py: OrderDiscoveryCollector 常驻后台任务(与 sweep 并列)。每隔
account_discovery_interval_seconds 派 order_list,收割结果后把「编目里没有的
订单」upsert 进编目,再逐笔派 order_detail 沉淀 delivery_status/order_state。
状态无痕:不新增编排跟踪表,仅内存 _pending + _detail_dispatched_this_day;
detail query_id 按天分段(discover-detail-<order>-<日期>),同天幂等防重复派。
边界:collector 只消费 worker 结果的规范化字段,绝不解析 raw/raw_pages。
- db.py: account_orders 表 + AccountOrderRow + upsert/single/list/stale 访问;
upsert 以 order_number 为主键,重复采集只刷新,列表重扫不抹详情节点。
- 路由: GET /api/account/orders(列编目)、GET /api/account/orders/{n}(6005)、
POST /api/account/discovery/trigger(手动立即派一轮 list)。
- config: RAKUTEN_ACCOUNT_DISCOVERY_ENABLED / _INTERVAL_SECONDS / _MAX_PAGES /
RAKUTEN_ACCOUNT_DETAIL_REFRESH_SECONDS。
- 既有网关测试夹具统一关 discovery(会启动即派扫描污染查询队列语义),
新表测试在 tests/test_gateway_discovery.py(13 用例,真实 QueryQueue+DB 装配)。
472 tests passed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -503,3 +503,69 @@ worker 回结果撞上 6006 属于正常情况(上一轮超时、单子已重
|
||||
- [x] 执行超时按失败回报,不把查询单挂到租约过期
|
||||
- [x] worker 任何异常都不逃出主循环,每张单都有一次回报
|
||||
|
||||
## 12. 定时下派通道:周期性发现账号订单并回写网关(2026-08-16)
|
||||
|
||||
### 12.1 解决什么
|
||||
|
||||
§11 的查询通道要拿订单详情,得**上游自己已经知道 order_number 再下派**。可账号在
|
||||
站点上可能走了别的渠道下单、被商家改状态,网关的状态镜像根本看不到。本通道让
|
||||
网关**自己定期盘点账号**:派一张 `order_list` 查询(走 §11 那条队列,本地 worker
|
||||
出站真读),把「网关编目里还没有的订单」**回写进新的 `account_orders` 表**,再逐笔
|
||||
派 `order_detail` 查询把配送阶段沉淀进去。之后上游直接查 `GET /api/account/orders`
|
||||
就能拿到账号里真实有哪些订单,不必自己记单号。
|
||||
|
||||
一句话:**gateway 从「等上游告诉它账号里有什么」变成「自己定时去账号里看,并把
|
||||
新订单写回自己」**。
|
||||
|
||||
### 12.2 实现与边界(最重要的两条)
|
||||
|
||||
**1. collector 只消费「规范化字段」,绝不解析站点原始 JSON。**「网关不解释
|
||||
query 的 params/result」这条原则照旧适用于上游自提的查询单;collector 自主派发的
|
||||
这批 `discover-*` 单是**网关自己的编排数据**,它们的结果里 worker 已经把
|
||||
`orders[].order_number/order_date/shop_id/shop_name` 与 `delivery_status/order_state`
|
||||
抽成了稳定契约字段(§11.3 明说这是「规范化字段是稳定契约」),collector 把它
|
||||
沉淀进编目不算解释站点内容。代码见 `app/gateway/collector.py::_parse_list_result`(
|
||||
只读这几个键)。
|
||||
|
||||
**2. 状态无痕(不新增任何编排跟踪表)。** collector 只在内存记「本进程派出去
|
||||
但还没处理结果」的 `_pending`;进程重启即清空,重启后下一轮 tick 派一张全新 list
|
||||
扫描,结果幂等 upsert 进编目,没有重复行。`order_detail` 的 query_id 用
|
||||
`discover-detail-<order_number>-<日期>` **按天分段**:同一天内重复 submit 命中幂等
|
||||
返回既有单(不会因每轮 tick 都满足「详情过期」而反复创建),跨天自然生成新单刷新
|
||||
详情;同一天内已派过详情的订单由 `_detail_dispatched_this_day` 在内存里挡掉,避免
|
||||
「found=False 订单一直算过期、每轮都重发」。已消费的 `discover-*` 查询单留在
|
||||
`account_queries`,由既有 sweep 按保留期(默认 7 天)清理。
|
||||
|
||||
### 12.3 接口
|
||||
|
||||
- `GET /api/account/orders?state=&limit=&offset=` — 列出编目订单,按最近出现倒序。
|
||||
编目行只含规范化字段(订单号/店铺/日期/配送状态),要看细节仍去拿对应订单的
|
||||
`order_detail` 查询单。
|
||||
- `GET /api/account/orders/{order_number}` — 单笔编目订单;编目里没有返回 6005。
|
||||
- `POST /api/account/discovery/trigger` — 手动立即派一轮 `order_list` 扫描
|
||||
(不等定时器到点),返回本轮下派的单号与 `created`。
|
||||
|
||||
collector 本身不回写「已经存在于下单任务表 `tasks` 的订单」——`account_orders` 是
|
||||
**账号真实订单的编目**,与 `tasks`(下单意图及其镜像)是两回事,两者通过
|
||||
`order_number` 天然对账(上游要确认「这单网上下了没」就是查 `tasks`,要「账号里
|
||||
实际有什么」就是查 `account_orders`)。
|
||||
|
||||
### 12.4 配置项
|
||||
|
||||
| 配置 | 默认 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `RAKUTEN_ACCOUNT_DISCOVERY_ENABLED` | true | 关闭则 collector 完全不启动 |
|
||||
| `RAKUTEN_ACCOUNT_DISCOVERY_INTERVAL_SECONDS` | 21600 | 两轮 `order_list` 扫描间隔(6h) |
|
||||
| `RAKUTEN_ACCOUNT_DISCOVERY_MAX_PAGES` | 3 | list 扫描翻页上限 |
|
||||
| `RAKUTEN_ACCOUNT_DETAIL_REFRESH_SECONDS` | 86400 | 单笔详情刷新间隔(24h) |
|
||||
|
||||
### 12.5 验收清单
|
||||
|
||||
- [x] 定时派 `order_list` / `order_detail`,结果落到 `account_orders` 编目
|
||||
- [x] 采集到编目中不存在的订单 → 回写新行;重复采集只刷新不重复
|
||||
- [x] 列表扫描不抹掉已取过的详情阶段(配送状态/详情时间保留)
|
||||
- [x] 同一天内同一订单的详情单只派一张;跨天自然刷新详情
|
||||
- [x] 手动 trigger 立即派一轮 list,返回的单在查询队列里可见
|
||||
- [x] `GET /api/account/orders` 列编目;单笔不存在返回 6005
|
||||
- [x] collector 只读规范化字段,不解析 raw/raw_pages 站点原始 JSON
|
||||
|
||||
|
||||
Reference in New Issue
Block a user