6.7 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 7344 | 管理端取消班期:order-v3 活跃订单聚合失败时不再落终态 CANCELLED,改取保守侧 CANCELLING(无接口、字段、路径、参数、枚举、错误码变化) | admin | jw(GIT) | 修复 | deployed | verified | not_required | mmg | 纯后端修复(PR #7348 合 dev-v3),接口/字段/路径/参数/枚举/错误码全不变,仅聚合失败路径落库 CANCELLED→CANCELLING。前端 grep 实证:CANCELLING/CANCELLED 走字典 schedule_status 直显(BatchPanel/BatchCard)本就同等排除,取消班期仅 cancelSchedule+confirm 无「等退款」反推,响应 code=200 结构不变。not_required 成立。 | 2026-09-08 | dev-v3 |
取消班期的活跃订单判据改 fail-closed(修复)
一、给前端的一句话
前端无需任何改动。 本次修复不动接口、不动字段、不动路径、不动参数、不动枚举、不动错误码。POST /admin/product/item/:id/schedule/:scheduleId/cancel 的响应在全部场景下仍是 code=200 / message="班期取消成功" / data=null;batchStatus 的取值集合(ENROLLING / NEARLY_FULL / FULL / FINISHED / CANCELLING / CANCELLED)与语义也不变。变的只是订单服务聚合失败时落库取哪一个取消态。
二、症状(改前)
管理端「取消班期」要先问 order-v3「这个班期还有没有活跃订单」,再决定落 CANCELLING(还有订单待订单域处理)还是 CANCELLED(确实没订单)。
这次取数走的是 fail-open 的降级路径:向 order-v3 的实时聚合一旦失败(Feign 超时 / 5xx / 返回 code != 200 / 目标班期缺席结果),失败分片的班期就退化为「无活跃订单」,活跃数被当成 0,班期于是被落成终态 CANCELLED。
后果不是钱退不出去(取消班期本来就不发起任何退款,见第五节),而是三件事:
- 状态语义错误:明明还有活跃订单的班期,被记成「已取消、无遗留」。
- 与订单域口径分裂:order-v3 流团触发的同语义入口(内部接口)早已收口为 fail-closed,两条路径对同一件事给出相反结论。
- 写错后不自愈:全仓没有任何路径会把
CANCELLED改回来——班期状态重算只在ENROLLING↔FULL之间流转、明确不碰取消态;编辑班期会保留原状态;订单域再次回调时对已取消态幂等直接返回。一旦写错,只能手工改库。
触发窗口窄(order-v3 抖动期间恰好有人点取消),但一旦命中就是永久性的错误状态。
三、修复(改后)
活跃数取数改用严格版本:聚合成功才按真实活跃订单数判定,聚合失败取保守侧 CANCELLING 并记一条 WARN 日志,与订单域内部入口逐字对齐。不新增任何接口、不新增任何方法。
| 场景 | 改前落库 batchStatus |
改后落库 batchStatus |
|---|---|---|
| 聚合成功且有活跃订单 | CANCELLING |
CANCELLING(不变) |
| 聚合成功且无活跃订单 | CANCELLED |
CANCELLED(不变) |
聚合失败(超时 / 5xx / code != 200 / 班期缺席结果) |
CANCELLED |
CANCELLING + 一条后端 WARN |
保守侧的代价是:order-v3 抖动窗口内被取消的空班期会显示「取消中」而不是「已取消」。这是刻意接受的——两个状态在全部下游判定里等价(下一节),差异只是展示文案;而反方向的错误会丢失「这批还有订单要处理」这一运营信号,且同样不自愈。
四、受影响接口(全部「复用不改」)
| 端 | 接口 | 变化 |
|---|---|---|
| 管理后台 | POST /admin/product/item/:id/schedule/:scheduleId/cancel |
method / path / 入参 / 出参 / 错误码均无变化;只有「聚合失败」这一条路径的落库值变了。Swagger notes 文案一并修正(原文误称「标记为 CANCELLING 触发退款」,实际不触发任何退款) |
| 管理后台 | GET /admin/product/item/:id/schedule/list |
无变化。仅作为取证入口,batchStatus 字段读到的就是上面落库的值 |
CANCELLING 与 CANCELLED 在下游四处判定中完全等价,前端已有的渲染逻辑不受影响:
- 班期展示态解析:两者都原样保留持久值,不参与实时库存重算
- 可报名谓词:两者都返回不可报名
- 下单选品列表:两者都被排除
- order-v3 下单闸:可下单状态只含
ENROLLING/NEARLY_FULL,两者都不在其中
五、澄清:取消班期不触发退款
修复顺带纠正了两处误导性文案(服务层注释与 Swagger notes)。它们原本写「CANCELLING → 触发退款 / 等退款流程异步处理」,但产品域取消班期的方法体只有一次班期状态落库,不发 MQ、不调 Feign、不发事件;全仓也没有任何代码读产品侧的 CANCELLING 去发起退款。团期退款实际由订单域的流团审批链路驱动。前端如果据旧文案做过「取消班期后等退款」的假设,可以去掉。
六、影响范围
- 只影响管理端「取消班期」这一个动作,且只在 order-v3 聚合失败时表现不同。
- 后端只滚
hl-product-service-v2;order-v3 / 网关 / 小程序端 / 其它服务一律不动。 - 无表结构变更、无 Flyway、无数据迁移;
group_tour_batch.batch_status的列定义与取值字典不变。
七、测试环境已验证
测试环境(api.test.1814.love)经真实网关实测三条路径,落库均以 SQL 复核:
| 路径 | 实测结果 |
|---|---|
| 无活跃订单 → 取消 | code=200,batchStatus=CANCELLED(不回归) |
| 真实下单后 → 取消 | code=200,batchStatus=CANCELLING(不回归) |
| 注入聚合失败 → 取消无订单班期 | code=200,batchStatus=CANCELLING,后端 WARN「取消班期: 活跃订单数聚合失败, 取保守侧 CANCELLING」 |
聚合失败用「只压单个 Feign 客户端超时」的方式构造,未停 order-v3;取证后配置已还原并复核一致。合并进 dev-v3 后又在 dev-v3 构建上复核过正常路径。本机单测 BUILD SUCCESS(1621 例,0 失败 0 错误),含新增的聚合失败用例与架构门禁。
关联 / 联系人
- 工单:https://git.1814.love:8443/wx/HL/issues/7344
- PR:https://git.1814.love:8443/wx/HL/pulls/7348 (合并提交 2071286a1 合入 dev-v3)
- 同源三单:#7283(订单域内部入口先行收口)、#7293(状态重算同构降级)、#7263(分片修复同一聚合链路)
- 后端:jw