文件
hl-api-changelog/changelogs-v2/2026-09/14_7666_接送机服务日回填CAS落空按库内真实值回显-内部接口-修复-管理后台.md
T
API Changelog Bot和Claude Opus 5 523c1faf99
changelog-filename-gate / validate (push) Failing after 2s
docs(changelog): #7666 接送机服务日回填(内部)CAS 落空按库内真实值回显(修复)
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
2026-09-14 22:37:38 +08:00

7.1 KiB
原始文件 Blame 文件历史

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(squash a37fd8b447) 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 的流程是:

  1. 先做一次快照读;
  2. 用大交通派生出服务日;
  3. 用 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 + 实际库里为空」的答复。如有据此跳过处理的批量脚本记录,建议对那批订单重跑一次回填端点。