changelog-filename-gate / validate (push) Failing after 2s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
11 KiB
11 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 | 8225 | 订单调整统一提交:远程调用移出锁与事务,新增失败码 587043「提交期间订单已被其他操作修改,请刷新后重试」 | admin | jw(GIT) | 修改接口 | deployed | verified | not_required | PR #8255 已合并 dev-v3(c2b261cd2),2026-09-23 15:40 滚动部署 TEST 双实例;其后另一会话部署的 f6d21648b 包含本单。真实网关实测:非法座位数提交返回 582024 且零写入,日志确认拒绝发生在拿锁之前;改出行人姓名正向往返 200 并落调整记录,已改回原值;无 token / 伪造 token 均 401。入参、出参结构不变,唯一的契约变化是新增失败码 587043;前端按通用失败提示展示后端 message 即可,无需改动。 | 2026-09-23 | dev-v3 |
订单调整: 统一提交的远程调用移出锁与事务 + 新增失败码 587043
存放目录: 二期(v3) →
changelogs-v2/2026-09/服务: hl-order-service-v3 PR: #8255 Issue: #8225 日期: 2026-09-23 影响范围: 管理后台订单详情「调整订单」弹窗的统一提交
⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写)
- 本次变化:统一提交接口多了一个失败码
587043「提交期间订单已被其他操作修改,请刷新后重试」。 - 前端以前以为的:同一订单两次调整并发提交时,后提交的那次会排队等前一次完成,然后照常成功。
- 实际新行为:算价、协议价、车型校验这些远程调用现在在拿锁之前完成。如果在这段时间里另一笔调整改了本单的出发日、人数或产品,本次提交会被拒绝并返回 587043,整笔不写库;用户刷新后重新提交即可。请求和响应的结构都没有变。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 调整订单统一提交 | POST | /v3/admin/order/:id/adjustment/submit |
新增失败码 | 新增 587043;入参、出参不变 |
三、接口详情
1. 调整订单统一提交 POST /v3/admin/order/:id/adjustment/submit
VO: AdjustmentSubmitReqVO → AdjustmentSubmitRespVO
使用场景
管理后台订单详情页「调整订单」弹窗,前端在内存里收集出行人、改期、行程、用房需求、行程用车、接送机用车等改动后一次性提交。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| Authorization | Header | String | ✅ | - | 管理端登录令牌 |
| id | Path | Long | ✅ | 订单须存在(581007) | 订单 ID |
| updates | Body | Object | ✅ | 至少一个子领域有实际改动(587033) | 各子领域修改内容,未改的子领域传 null |
| updates.people | Body | Object | ❌ | - | 订单级紧急联系人 + 出行人增删改 |
| updates.travelers | Body | Object | ❌ | - | 出行人 add / update / remove |
| updates.schedule | Body | Object | ❌ | departDate 为 yyyy-MM-dd |
改期 |
| updates.itinerary | Body | Object | ❌ | - | 行程天与节点的完整新版本 |
| updates.hotelRequirement | Body | Object | ❌ | - | 用房需求完整新版本 |
| updates.vehicleRequirement | Body | Object | ❌ | fleet 车型须为车型大类、座位数须在车型库选项内 | 行程用车需求完整新版本 |
| updates.transferRequirement | Body | Object | ❌ | 同上 | 接送机用车需求完整新版本 |
出参 Result<AdjustmentSubmitRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| success | Boolean | 提交成功恒为 true |
请求示例
{
"updates": {
"travelers": {
"update": [{ "id": "2098374040010772481", "name": "杨知川" }]
}
}
}
响应示例
{ "code": 200, "message": "成功", "data": { "success": true }, "traceId": null, "success": true }
空数据 / 降级响应
写接口没有空数据场景。所有提交都没有实际改动时返回 587033,零写入:
{ "code": 587033, "message": "未检测到有效变更,无需提交", "data": null, "traceId": null, "success": false }
错误响应
本次新增:
{ "code": 587043, "message": "提交期间订单已被其他操作修改,请刷新后重试", "data": null, "traceId": null, "success": false }
既有错误码照旧,例如车型座位数不合法:
{ "code": 582024, "message": "座位数不在该车型大类可选座位数中,请检查车型库", "data": null, "traceId": null, "success": false }
业务边界
- 鉴权:未登录 → 业务码
401(「缺少有效的 Authorization 头」),token 签名不对 →401(「Token 无效」)。 - 587043 只在「本次提交读到的订单」与「拿锁后的订单」在出发日、人数、产品上不一致时出现,也就是有另一笔调整恰好在同一时刻提交;单人操作不会遇到。
- 587043 与其它失败码一样整笔零写入,重新提交会按最新的订单状态重新计算差价。
四、契约约束与正确调用方式(接口类必写)
本节只写后端接受/拒绝 payload 的规则,不写 UI 渲染建议。
✅ 正确 / ❌ 错误 payload 对照
| 场景 | payload | 结果 |
|---|---|---|
| ✅ 只改出行人姓名 | updates.travelers.update=[{id,name}] |
200 |
| ❌ 没有任何实际改动 | updates: {} |
587033 |
| ❌ 行程用车座位数不在车型库选项内 | fleet=[{vehicleType:"大巴", seats:999, count:1}] |
582024,零写入 |
| ❌ 提交期间另一笔调整改了出发日 / 人数 / 产品 | 任意 | 587043,零写入(本次新增) |
- 请求与响应结构没有任何变化;587043 的
message已写明处理方式,前端按通用失败提示展示后端文案即可。
五、数据库行为(涉及写操作时必写)
- 无 Flyway migration、无 DDL、无表结构变更。
- 写库集合与改前一致(出行人、行程、用房/用车需求版本、优惠加费、调整记录、状态日志),仍在同一个事务内原子完成。
- 变化在事务边界:算价、协议价、车型校验等远程调用改为在拿锁、开事务之前完成,订单行与用车确认 fence 行的锁持有时间不再包含这些远程往返。
- 任何失败(含新增的 587043)都在写库之前抛出,整笔零写入。TEST 实测:非法座位数提交后,订单主单、fence 行、用车需求、调整记录前后逐字段一致。
六、边界行为
- 未登录 → 业务码
401。 - 越权规则不变:非管理员只能调整自己负责的订单。
- 拒绝原因的先后顺序不变:终态、已过天锁定、出行人/改期窗口、改期日期格式等守卫,仍然先于算价与车型校验。
- 团期子订单改期仍只能改回所属团期出发日(587039),不走个人价格日历报价。
六.6、修改前后对比(修改/删除类接口必写,新增跳过)
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
| 请求体 | AdjustmentSubmitReqVO |
不变 |
| 响应体 | { success } |
不变 |
| 失败码 | 无 587043 | 新增 587043 |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 远程调用(算价、协议价、车型字典/座位、字典标签)发生时机 | 拿锁、开事务之后 | 拿锁、开事务之前 |
| 两笔调整并发提交,前一笔改了出发日/人数 | 后一笔等锁后按新状态照常执行 | 后一笔返回 587043,刷新重提 |
| 车队 / 产品 / 资源服务响应慢 | 订单行被锁住直到远程返回 | 不影响锁持有时间 |
六.7、影响评估(修改/删除类必写)
- 是否破坏向后兼容:请求、响应结构不变;只新增一个失败码,只在并发调整同一订单时出现。
- 前端是否必须同步上线:否。前端的通用失败提示会展示后端
message(「提交期间订单已被其他操作修改,请刷新后重试」),无需改动。 - 前端 workaround 清理点:无。
七、不影响范围(显式声明, 帮前端/QA 缩小排查面)
- 仅影响:
POST /v3/admin/order/:id/adjustment/submit的内部执行顺序,以及新增失败码 587043。 - 零影响:
GET /v3/admin/order/:id/adjustment/snapshot(调整弹窗初始化数据)与GET /v3/admin/order/:id/adjustment-record(调整记录)。- 行程查询
getItinerary返回的服务标准字段、大交通批次列表的旅客类型中文名(管理端读接口行为不变)。 - 既有失败码与文案。
八、测试环境已验证
部署:PR #8255 合并 dev-v3(c2b261cd2),2026-09-23 15:40 滚动部署 TEST 双实例;其后另一会话部署的 f6d21648b 以本单为祖先,且其间没有提交改动本单涉及的文件。
真实网关(https://api.test.1814.love,管理端 token,订单 2098372757820428289):
POST /v3/admin/order/:id/adjustment/submit 无 token → 401 缺少有效的 Authorization 头 ✓
POST /v3/admin/order/:id/adjustment/submit 伪造 token → 401 Token 无效 ✓
POST ... updates={} → 587033 未检测到有效变更 ✓
POST ... vehicleRequirement.fleet=[大巴 × 999 座] → 582024,订单/fence/用车需求/调整记录前后一致 ✓
同时刻 primary 实例日志:先是不加锁的 order_main 查询,全程 0 条 fence SQL、0 条 FOR UPDATE ✓
POST ... travelers.update 改姓名 → 200,姓名已改、调整记录 0→1 ✓
POST ... travelers.update 改回原名 → 200,姓名还原 ✓
587043 需要两笔调整真实竞态才能触发,TEST 上未造出;由单元测试覆盖(两段之间出发日变化 → 587043 且零写入;出发日未变 → 放行的对照)。
单元测试:rebase 后定向 239 类 / 3290 例 0 失败,含 AdjustmentServiceSubmitTest 86、TransactionalRemoteCallArchTest 2、SettlementLockContractTest 5。
十、相关文档
- 关联 Issue: wx/HL#8225
- 关联 PR: wx/HL#8255
- 上游来源:#8202(CR 带出本单)