文件
hl-api-changelog/changelogs-v2/2026-10/23_9201_核单车辆费用写入明细条数上限-修改接口-管理后台.md
T
2026-10-23 11:02:06 +08:00

8.4 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 9201 核单车辆费用写入内部接口:明细条数上限 2000,超限写库前失败 605610 internal chewu3(GIT) 修改接口 deployed not_required not_required 唯一调用方 order-v3 的合法载荷上界 2000 条(逐日派车拓扑不变量);当前冻结写入口另有更紧的 1000 条审计上限。超限在首次数据库副作用之前抛 605610,消息含实际条数与上限,零部分写入。已随 dev-v3 57de68b70 部署 TEST(task 5c950897),两实例 UP。 2026-10-23 dev-v3

hl-fleet-service: 核单车辆费用写入明细条数设上限

服务: hl-fleet-service(内部 Feign 口,网关不放行) PR: #9208(已合入 dev-v3,合并提交 57de68b70) Issue: #9201


⚠️ 关键变化

🟢 POST /internal/fleet/reconciliation/vehicle-fee 的 items 新增条数上限 2000:超过即返回 605610,且在取数据库栅栏、判关账、任何 upsert 之前失败——不会出现部分明细已写入。

🟢 锁租约由 30s 延长到 120s(服务端 Redis 租约,调用方不可见)。原因:2000 条最坏 7 次 DB 往返/条 ≈ 14000 次,30s 在慢库下不够。

🔴 此前无上限:调用方传入多少条就逐条写多少条,持锁时间随笔数线性增长,可能超过租约后仍继续写库。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 核单车辆费用写入 POST /internal/fleet/reconciliation/vehicle-fee 请求体新增条数上限 items > 2000 返回 605610,零写入

三、接口详情

1. 核单车辆费用写入 POST /internal/fleet/reconciliation/vehicle-fee

VO: SettlementVehicleFeeWriteDTO(hl-common-core,唯一调用方 order-v3)

使用场景

order-v3 结账冻结车辆费用后,经命令发件箱异步把逐日车辆费用明细回传车务落库(OrderFleetCommandOutboxProcessor → FleetAssignmentExpandFeignClient#writeSettlementVehicleFee)。一条 items 对应订单侧一条 FLEET_DAILY 冻结行,服务端逐条按 (orderId, assignmentId, serviceDate) 唯一键 upsert。

入参

字段 位置 类型 必填 约束 说明
orderId / orderNo Body Long / String ✅ - 订单身份
settledAt Body LocalDateTime 否 - 结账时刻
items Body List ✅ 1~2000 条(新增上限) 每条一个 assignmentId + serviceDate
items[].assignmentId Body Long ✅ - 车务派车行 ID
items[].driverId Body Long ✅ - 司机
items[].serviceDate Body LocalDate ✅ - 服务日
items[].actualAmount Body BigDecimal ✅ 两位小数 该日实际车费
items[].vehicleId Body Long 否 - 为空时跳过车辆快照校验

出参

字段 类型 说明
code / message / success - 成功 200;超限 605610
data null 本接口无业务返回体

请求示例

POST /internal/fleet/reconciliation/vehicle-fee HTTP/1.1
Host: hl-fleet-service
Content-Type: application/json

{
  "orderId": 2112275846201069569,
  "orderNo": "SO202610230001",
  "settledAt": "2026-10-23 10:30:00",
  "items": [
    { "assignmentId": 9001, "driverId": 501, "serviceDate": "2026-10-28", "actualAmount": "1500.00", "vehicleId": 4401 }
  ]
}

响应示例

{ "code": 200, "message": "成功", "data": null, "success": true }

空数据 / 降级响应

items 为空数组时维持原行为:只记一条 info 日志,直接返回 200,不写库。服务端降级不适用于本接口(失败即整笔失败,由发件箱重放)。

错误响应

超过 2000 条(新增):

{
  "code": 605610,
  "message": "核单车辆费用写入明细条数超过上限:实际 2001 条,上限 2000 条(orderId=… orderNo=…)",
  "success": false,
  "data": null
}

单条结构非法(645610 同码族、原有行为):605610 + 具体缺字段说明。

业务边界

  • 条数检查在 @Lock4j 租约之后(AOP 时序)、数据库栅栏与全部写库之前;超限请求不产生任何行级写入。
  • 上限 2000 取自 FleetAssignmentPlanConstants.MAX_DAILY_PLAN_CELLS(逐日派车拓扑硬不变量),不是拍脑袋值:调用方每条 items 来自一条冻结 FLEET_DAILY 行,而冻结行数受同一拓扑校验约束。
  • 当前冻结写入口另按 VehicleFeeAuditSnapshot.MAX_AUDIT_ITEMS = 1000 限制,故正常新单实际不会到 2000;上限留 2 倍余量,避免误拒更早历史数据形成的大单。

四、契约约束与正确调用方式

  • 一次请求的 items 必须 ≤ 2000,且不要把「整团全部历史日期」拼进同一次写入来绕开分页。
  • 超限返回是可判定的拒绝:调用方应记录实际条数并告警,不要盲目重试同一 payload(重试仍 605610)。
  • 调用方 Feign 默认 readTimeout=30000:2000 条慢库档(3~5ms/次往返)可能超过 30s,超时后按发件箱重放;服务端 upsert 以 (orderId, assignmentId, serviceDate) 唯一键收敛,重放不会产生重复行。

五、数据库行为

场景 结果
items ≤ 2000 逐条 upsert(先按唯一键查,有则 update,无则 insert)
items > 2000 零写入,直接 605610

六、边界行为

  • 恰好 2000 条:照常写入(上限含边界)。
  • items=null 或空数组:不触发上限检查,原行为返回 200。
  • 判断发生在 Redis 租约之后是已知取舍(租约由 AOP 在方法体前取得);业务副作用(数据库栅栏、关账判断、写行)全在检查之后。
  • 锁键 fleet:recon-vehicle-fee:{orderId}、事务边界、章节锁序均未改,仅 expire 30s→120s。

六.6、修改前后对比

场景 改前 改后
items = 2001 逐条写 2001 行,持锁时间不受控 605610,零写入
items = 2000 逐条写入(可能超过 30s 租约) 逐条写入,租约 120s
items 为空 200,info 日志 同左(不变)

六.7、影响评估

  • 是否破坏向后兼容:否。唯一调用方 order-v3 的合法载荷上界 2000,正常链路不触发新拒绝。
  • 调用方是否必须同步上线:否。
  • 回滚:revert #9208 并重部署 hl-fleet-service,恢复 30s 租约与无上限行为。

七、不影响范围

  • 其他 /internal/fleet/reconciliation/** 接口、保险费用写入、关账判断逻辑。
  • 单条 upsert 语义与唯一键(未改动)。
  • 管理后台核单页面与前端契约(零变化)。

八、测试环境已验证

环境:TEST 验证时间:2026-10-23 10:39~10:45 构建身份:hl-fleet-service dev-v3 @ 57de68b70,部署 task 5c950897;两实例 8187/8087 is UP after 7s;部署状态回读 dev-v3 57de68b70 0/N ok。

本接口不经网关、唯一调用方为 order-v3,测试服未做载荷级直连实测;契约由以下读数支撑:

  • 单元:ReconciliationVehicleFeeServiceTest 14 例 0 失败,含 write_itemsOverCap_throws605610BeforeAnyFenceOrWrite(2001 条 → 605610、消息含 2001/2000、断言零 DB 交互)与 write_itemsAtCap_passesGuardAndWritesEveryRow(2000 条照常写 2000 行)。
  • 变异:把边界改成 <= 上限+1 → 两条用例红(Expecting code to raise a throwable),还原后 14 例复绿。
  • 冒烟:网关只读探活 GET /admin/fleet/dispatch-groups/page 200 + 3 个团详情 200(CHECKED=3 FAIL=0);两实例部署窗口日志 total_ERROR=0。

十、相关文档

  • Issue #9201;PR #9208
  • 门禁与量化过程见 E:/work/reports/9201/收口报告.md(2000 上界推导、单条 3/5/7 次 DB 往返、租约余量)

关联 / 联系人

链接

联系人

  • 后端负责人: @chewu3