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 | 8598 | 派单保险隔离事件新增人工终结(DISCARDED)出口 | admin | wx(GIT) | 新增接口 | deployed | not_required | not_required | 新增 POST /admin/fleet/insurance/assignment-events/{eventId}/discard,仅 SUPER_ADMIN 可调用,把处于 QUARANTINED 的派单保险隔离事件人工终结为新终态 DISCARDED,终结不可逆、无回退入口,也无批量接口,逐条操作且终结原因必填(非空、≤200字)。幂等窗口10秒(重复提交返100502),并发冲突返100503(CAS未命中)。DISCARDED 会让关联的行程短信状态查询/重发端点(GET及POST .../itinerary-sms[/retry])对该事件返回 status=FAILED、canRetry=false——这是已有取值组合,不引入新字段或新枚举值,前端已有的 FAILED 分支即可覆盖,不需要新增代码路径。gateway_status=not_required,复用既有 /admin/fleet/** 路由,未新增网关配置。backend_status=deployed:PR #8607(合并提交5afadf6c634)已合并,hl-fleet-service 已部署测试服并与本条目所依据的源码提交一致(deploy-status.sh 实测 COMMIT=d57498d38,STATE=ok,2026-09-30 05:34:07 部署);未登录态 curl 实测该路径已挂载并优先鉴权(返 200 信封 code=401,非 HTTP 401 状态码),路由与鉴权链路均已验证。;前端实证:hl-admin 全仓零 assignment-events/itinerary-sms 封装,QUARANTINED 仅 spec fixture,无消费点,判 not_required(hl-admin sync-log 2026-09-30) | 2026-09-30 | dev-v3 |
车务保险: 隔离事件新增人工终结(DISCARDED)出口
存放目录: 二期(order-v3)→
changelogs-v2/2026-09/服务: hl-fleet-service(端口 8087) PR: #8607 Issue: #8598 日期: 2026-09-30 影响范围: 超管对派单保险隔离 Outbox 事件的处置面板,新增一个终结动作;对既有重放端点与行程短信状态端点零结构变化
⚠️ 关键变化
隔离事件(QUARANTINED)此前唯一的出口是重放——重放会再隔离的事件(关联需求已删、内容审核不过、上游数据已按别的单清理),会让卡死告警永久为红,没有任何办法让它退出告警。本次新增一个人工终结动作,把这类确定性失败的事件显式标成新终态 DISCARDED,终结之后它退出卡死告警、不再被扫描器捞起、也不再阻塞同 orderingKey 的后继事件。终结无回退入口,是单向不可逆操作。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 终结已隔离的派单生命周期事件 | POST | /admin/fleet/insurance/assignment-events/{eventId}/discard |
新增接口 | 仅 SUPER_ADMIN,QUARANTINED → DISCARDED |
三、接口详情
1. 终结已隔离的派单生命周期事件 POST /admin/fleet/insurance/assignment-events/{eventId}/discard
VO: AssignmentInsuranceOutboxDiscardReqVO → AssignmentInsuranceOutboxDiscardRespVO
使用场景
超管在派单保险 Outbox 卡死告警/隔离事件处置面板里,对一条已确认「重放多少次都会再隔离」的事件(例如关联需求已随团期撤销删除、内容审核不通过、上游数据已被另一张单清理)执行终结,承认这个业务动作确实不会再发生、也不再补,并把原因、操作人、时间留痕。与重放动作共用同一批隔离事件列表数据源,本次不新增查询端点。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| eventId | Path | Long | ✅ | - | Outbox 事件 ID |
| reason | Body | String | ✅ | 非空;≤200 字 | 确认不再重放的原因,须说明业务影响已如何处置 |
出参 Result<AssignmentInsuranceOutboxDiscardRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| eventId | String(Long 转字符串) | Outbox 事件 ID |
| previousStatus | String | 终结前状态,恒为 QUARANTINED |
| status | String | 终结后状态,恒为 DISCARDED |
| operatorId | String(Long 转字符串) | 操作人管理员 ID |
| discardedAt | String | 终结操作时间,格式 yyyy-MM-dd HH:mm:ss |
请求示例
{
"reason": "关联需求已随团期撤销删除,短信不再需要补发"
}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"eventId": "1934567890123456789",
"previousStatus": "QUARANTINED",
"status": "DISCARDED",
"operatorId": "88",
"discardedAt": "2026-09-30 10:20:30"
},
"success": true
}
空数据 / 降级响应
本接口是单事件的状态迁移动作,没有「空数据」或部分成功的中间态——调用结果只有「成功迁移」或下方错误响应里的某一种拒绝,不存在降级返回。
错误响应
{
"code": 403001,
"message": "无权限,仅超级管理员可终结隔离事件",
"success": false,
"data": null
}
其余可能返回的错误码:
| code | 触发条件 | message |
|---|---|---|
| 400 | reason 为空白或超过 200 字(Bean Validation,先于业务逻辑拦截) |
终结原因不能为空 或 终结原因最多200字 |
| 100001 | eventId 对应事件不存在 |
参数非法: 隔离事件不存在 |
| 100001 | 事件当前状态不是 QUARANTINED(已是 SUCCESS/DISCARDED/PENDING/PROCESSING) |
参数非法: 仅允许终结 QUARANTINED 事件,当前状态为{实际状态} |
| 100502 | 同一 eventId 10 秒幂等窗口内重复提交 |
隔离事件终结中,请勿重复提交 |
| 100503 | 并发命中 CAS 未命中(他人同时终结/重放,或处理器抢先处理) | 资源被占用,请稍后重试 |
| 401 | 未登录(网关统一信封,HTTP 状态码仍是 200,信封内 code=401) |
缺少有效的 Authorization 头 |
业务边界
- 只接受当前状态为
QUARANTINED的事件;其余状态一律 100001 拒绝。 - 终结是单向操作,没有「撤销终结」的接口。
- 无批量终结接口,只能逐条调用——设计上刻意如此:批量会把混在隔离事件里的真实业务缺口一次性静默抹掉。
- 幂等键为
eventId(10 秒窗口),并发保护为乐观锁 CAS;两者返回的错误码不同(100502 vs 100503),前端应分别处理:100502 提示稍候,100503 建议重新拉取该事件当前状态后再决定下一步。 - 终结成功后,该事件对应的行程短信状态查询/重发端点(
GET /admin/fleet/assignments/{assignmentId}/itinerary-sms、POST .../itinerary-sms/retry)会返回status=FAILED, canRetry=false——这是这两个端点已公开枚举值集合里已有的取值组合,不是新增字段或新增枚举值,前端已有的FAILED分支不需要改动即可正确渲染。
四、契约约束与正确调用方式
本节只写后端接受/拒绝 payload 的规则,不写 UI 渲染建议。
✅ 正确 / ❌ 错误 payload 对照
| 场景 | payload | 结果 |
|---|---|---|
| ✅ 原因非空且 ≤200 字 | { "reason": "关联需求已随团期撤销删除,短信不再需要补发" } |
200,事件迁移为 DISCARDED |
| ❌ 原因为空 | { "reason": "" } 或 { "reason": " " } |
400 终结原因不能为空 |
| ❌ 原因超长 | { "reason": "<201 个字符>" } |
400 终结原因最多200字 |
| ❌ 对非 QUARANTINED 事件调用 | 任意合法 reason,但目标事件当前是 SUCCESS/DISCARDED/PENDING/PROCESSING | 100001,message 里点名当前状态 |
调用前置
调用前前端应确认目标事件当前处于「已隔离」状态(面板上通常是从隔离事件列表点进来),不要对已经终结过、已成功、或还在处理中的事件发起终结请求——这些情形不会被静默忽略,而是显式返回 100001。
五、数据库行为
- 终结成功后,该事件状态字段变为
DISCARDED;原因、操作人、操作时间会被记录(复用重放动作已有的三个字段承载,未新增列)。 - 终结成功后再对该事件调用既有的重放端点(
POST /admin/fleet/insurance/assignment-events/{eventId}/replay),会返回 100001「仅允许重放 QUARANTINED 事件,当前状态为DISCARDED」。 - 终结不会产生任何下游消息重放或补发——它就是承认这件事不会再发生。
六、边界行为
- 未登录 → 网关统一信封
code=401(HTTP 状态码 200,非 HTTP 401) - 非超管 → 403001
eventId不存在 → 100001- 事件状态非
QUARANTINED→ 100001,message 带当前实际状态 reason为空/超长 → 400(Bean Validation 先于业务逻辑拦截)- 10 秒幂等窗口内重复提交同一
eventId→ 100502 - 并发命中 CAS 未命中 → 100503
- 下游服务降级 → 不适用,本接口无下游读取,只做本域状态迁移
六.5、枚举 / 数据字典
status / previousStatus(AssignmentInsuranceOutboxStatusEnum)
所属字段: status / previousStatus(AssignmentInsuranceOutboxDiscardRespVO) | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
PENDING |
待处理 | 尚未开始处理(本接口不接受此状态) |
PROCESSING |
处理中 | 正在处理(本接口不接受此状态) |
QUARANTINED |
已隔离 | 卡死告警状态,唯一可被本接口终结的状态;previousStatus 恒为此值 |
SUCCESS |
成功 | 机器判定的成功终态(本接口不接受此状态) |
DISCARDED |
已终结(本次新增) | 人工判定的放弃终态,只能由本接口产出,单向不可逆;status 恒为此值 |
七、不影响范围
- 仅影响: 派单保险隔离 Outbox 事件处置面板,新增一个终结动作入口
- 零影响:
- 既有重放端点
POST /admin/fleet/insurance/assignment-events/{eventId}/replay的路径、参数、错误码 - 既有隔离事件列表/卡死告警统计查询
- 行程短信状态查询/重发端点的响应字段结构与已公开枚举值集合(新增的只是一条已有取值组合被触发的路径)
- 既有重放端点
八、测试环境已验证
deploy-status.sh(测试服现状表)实测:hl-fleet-serviceCOMMIT=d57498d38、STATE=ok,2026-09-30 05:34:07 部署——与本条目所依据的源码提交(含 #8598 合并提交5afadf6c634)一致。- 测试服内网
curl实测路由已挂载且鉴权前置生效:
POST http://127.0.0.1:8080/admin/fleet/insurance/assignment-events/1/discard (无 Authorization 头)
→ HTTP 200
{"code":401,"message":"缺少有效的 Authorization 头","data":null,"traceId":"f3e71e825f844525","success":false}
十、相关文档
- 关联 Issue: wx/HL#8598
- 关联 PR: wx/HL#8607
关联 / 联系人
链接
- Issue: #8598
- PR: #8607
- Merge commit:
5afadf6c634
联系人
- 后端负责人: @wx