POST /v3/internal/order/orders/{orderId}/requirement/transfer/service-dates/backfill:CAS 落空时按库内当前读作答,
库内仍空答 NO_TRANSPORT(不再失真答 ALREADY_PRESENT),库内有日期答 ALREADY_PRESENT + 库内真实值。
补正 13_7439 内部分册第 4 个端点的 outcome 口径。测试服 order-v3 dev-v3@79e3b9da7 直连实例实测。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015LU2ERekNLbvhsMqzFruHo
7.1 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 | 7666 | 接送机服务日回填(内部):CAS 落空时按库内真实值回显,NO_TRANSPORT 多一种成因 | internal | wx(GIT) | 修复 | deployed | not_required | not_required | 内部接口(/v3/internal/**,不经网关),收件人是后端调用方(#7443 展开前置、运维批量补数脚本),不是 mmg。不改请求/响应结构、不新增 outcome 取值、不新增错误码;只改 CAS 落空这一分支的 outcome 与 serviceDates 取值口径。本文件补正 13_7439_团期车务地基-内部接口-修改接口-管理后台.md 第 4 个端点的 outcome 说明。 | 2026-09-14 | dev-v3 |
order-v3: 接送机服务日回填(内部)CAS 落空后按库内真实值回显(修复)
服务: hl-order-service-v3(
RequirementService#backfillTransferServiceDates→fillCasMissOutcomeFromDb) 消费方: 后端内部调用方(#7443 展开前置、运维批量补数脚本),/v3/internal/**不经 JWT、网关不暴露 PR: #7692(squasha37fd8b447) Issue: #7666 日期: 2026-09-14 影响范围: 1 个内部接口的一个分支(首次读为空、派生出日期、但 CAS 匹配 0 行);不涉及请求/响应结构、outcome 取值集合、错误码、路由与数据库
⚠️ 关键变化
🔴 CAS 落空时不再无条件答 ALREADY_PRESENT,改为按库内当前读的真实值作答。
| 情形 | 改动前 | 改动后 |
|---|---|---|
| CAS 落空,库内该行此刻有服务日 | ALREADY_PRESENT,serviceDates = 本次调用自己派生的日期(可能与库内不同) |
ALREADY_PRESENT,serviceDates = 库内真实值 |
CAS 落空,库内该行此刻仍为空(NULL 或 []) |
ALREADY_PRESENT,serviceDates = 本次派生的日期(失真:库里其实没有) |
NO_TRANSPORT,serviceDates=[] |
| CAS 落空,重读时已无活跃 TRANSFER 需求 | ALREADY_PRESENT |
NOT_FOUND,requirementId=null,serviceDates=[] |
| 首次读就有服务日 / 回填成功 / 无活跃需求 / 派生不出日期 | 各自原样 | 不变 |
🟢 CAS 没有落空的三种正常结局(BACKFILLED / 首次读 ALREADY_PRESENT / 派生不出的 NO_TRANSPORT)与 NOT_FOUND,逐字段不变。
一、背景
backfillTransferServiceDates 的流程是:
- 先做一次快照读;
- 用大交通派生出服务日;
- 用
WHERE status = 'PENDING_REVIEW'做 CAS 写回。
CAS 匹配 0 行,说明这一行在首次读之后被别的操作推离了 PENDING_REVIEW。推走它的操作不一定写了服务日,它可能是提交车务、打回或其他写口。
改动前,这个分支一律按「本来就有」作答,并把自己派生的日期当成库内的值返回。调用方拿到 ALREADY_PRESENT 就会继续调严格 GET,而库里可能仍是空的,于是在下一步被 809007 打掉。更糟的是,调用方会以为这一单「不用再管」。
本单改为:CAS 落空后,对同一行做一次当前读(selectLatestByOrderIdForUpdate),按库内真实值作答。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 回填接送机服务日(内部) | POST | /v3/internal/order/orders/{orderId}/requirement/transfer/service-dates/backfill |
修复 | CAS 落空分支按库内当前读作答 |
三、接口详情
1. 回填接送机服务日(内部)
- 方法 / 路径:
POST /v3/internal/order/orders/{orderId}/requirement/transfer/service-dates/backfill - 路径参数:
orderId(订单 ID) - 请求体:无,不变
- 鉴权:请求头
X-Internal-Token,不变 - 响应:
Result<TransferServiceDatesBackfillRespVO>,字段requirementId/outcome/serviceDates,结构不变 - 错误码:不新增
outcome 取值口径(补正 #7439 内部分册第 4 个端点的说明):
| outcome | 含义(改动后) |
|---|---|
BACKFILLED |
本次补齐服务日并推进 PENDING_REVIEW → PENDING;serviceDates 为本次写入的值 |
ALREADY_PRESENT |
库内该行确有非空服务日,本次未改动;serviceDates 为库内值(首次读就有,或 CAS 落空后当前读到了) |
NO_TRANSPORT |
本次未写、未推状态,且库内该行仍没有服务日。两种成因:①大交通派生不出日期,该行停在 PENDING_REVIEW;②CAS 落空(该行已被推离 PENDING_REVIEW)后回读,库内仍为 NULL 或 [] |
NOT_FOUND |
无活跃 TRANSFER 需求(首次读即无,或 CAS 落空后回读时已无);requirementId=null |
请求 / 响应实测原文:
- 环境:2026-09-14,测试环境,直连实例
http://192.168.100.236:8086(内部接口不经网关)。 - 部署:
hl-order-service-v3为dev-v3@79e3b9da7,含本单,部署时间 21:59:54。 - 数据:前置状态由 SQL 直更构造,事后已还原。
① CAS 落空、库内有日期。另一连接持行锁,把该行改为 DONE + 哨兵日期 2099-01-01 后提交;返回的是库内哨兵值,不是本次派生的日期:
POST /v3/internal/order/orders/2098381524394024962/requirement/transfer/service-dates/backfill
HTTP 200
{"code":200,"message":"成功","data":{"requirementId":"2098381840044761089","outcome":"ALREADY_PRESENT","serviceDates":["2099-01-01"]},"traceId":null,"success":true}
② CAS 落空、库内仍为空。该行已是 PENDING,service_dates 为 NULL,大交通能派生出日期:
POST /v3/internal/order/orders/2098372734110027778/requirement/transfer/service-dates/backfill
HTTP 200
{"code":200,"message":"成功","data":{"requirementId":"2098959908610183170","outcome":"NO_TRANSPORT","serviceDates":[]},"traceId":null,"success":true}
③ 回归,回填成功:
POST /v3/internal/order/orders/2098374023258722305/requirement/transfer/service-dates/backfill
HTTP 200
{"code":200,"message":"成功","data":{"requirementId":"2098959909633593346","outcome":"BACKFILLED","serviceDates":["2026-09-11","2026-09-18"]},"traceId":null,"success":true}
四、调用方需要做什么
- 分流规则不变:
NO_TRANSPORT→ 就地失败关闭,不得再调GET .../requirement/vehicle?kind=TRANSFER;BACKFILLED/ALREADY_PRESENT→ 可以继续调 GET。
- 不要再把
NO_TRANSPORT解读成「客人一定没填大交通」:它现在也可能表示「这一行被别的写口推走了,库里仍没有日期」。只要按上面的分流规则就地失败关闭即可;如需区分成因,看 order-v3 日志里的接送机服务日回填 CAS 落空且库内仍无服务日(WARN,带status)。 - 改动前,调用方在并发下可能拿到过「
ALREADY_PRESENT+ 实际库里为空」的答复。如有据此跳过处理的批量脚本记录,建议对那批订单重跑一次回填端点。