文件
hl-api-changelog/changelogs-v2-mp/2026-10/03_8739_小程序团期下单撞改期联动时等锁并返回资源占用码-修改接口-小程序端.md
T
API Changelog Bot和Claude Opus 5.5 5995966e1d
changelog-filename-gate / validate (push) Failing after 2s
docs(mp): 小程序团期下单撞改期联动时等锁 5 秒并返回 100503(#8739)
Refs #8739

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-03 03:33:44 +08:00

14 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 8739 小程序团期下单撞上改期联动时最多等 5 秒,超时返回 100503,不再误报请勿重复提交 mp wx(GIT) 修改接口 deployed not_required pending 2026-10-03 dev-v3

小程序团期下单撞上改期联动时最多等 5 秒,超时返回 100503,不再误报请勿重复提交

⚠️ 关键变化

  • 场景:POST /mp/order/create 带 groupBatchId 下团期单,而管理端此刻正在给该团期「改出发日」并联动订单(#8666 引入的联动)。

    • 下单会先等联动结束,最多等 5 秒。
    • 5 秒内联动结束:按改后的日期正常成单,响应比平时慢几秒。
    • 5 秒后联动仍未结束:返回 100503「资源被占用,请稍后重试」,不成单,可以直接重提。
  • 改前(#8666 上线后、本次之前),同一场景下小程序约 3.5 秒就收到 100502「请勿重复提交订单」。测试服实测:

    • 联动在 5 秒内结束时,后台其实已经成单;
    • 联动占用超过 5 秒时,没有成单。

    也就是说,这条路径上的 100502 既可能是「成了」,也可能是「没成」。本次起这条路径不再返回 100502。

  • 小程序服务等订单服务的上限由 2 秒放宽到 10 秒,超时后也不再自动重发下单请求。

    • 超过 10 秒仍无结果时,返回 500「服务暂时不可用,请稍后重试」。
    • 此时订单服务端的那次创单不会因此中止,订单可能已经生成。
  • 不带 groupBatchId 的下单不等联动、不会多等。10 秒上限和「不自动重发」对它同样适用。

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 创建订单 POST /mp/order/create 错误响应语义变更 团期下单撞上改期联动时最多等 5s,超时返 100503,该路径不再返 100502;服务端超过 10s 返 500,不再自动重发

三、接口详情

1. 创建订单 POST /mp/order/create

VO: MpCreateOrderRequest → MpOrderDetailVO

使用场景

用户在产品详情页选好档位、人数并填好联系人后提交下单。

  • 本次只改变下单失败和变慢时返回什么。
  • 对带 groupBatchId 的团期单影响最大:该团期正被管理端改出发日时,下单会先等联动结束。

入参

字段 位置 类型 必填 约束 说明
productId Body String 是 不能为空;必须是数字字符串,否则返回 600002「产品ID格式错误」 产品 ID(对外收字符串,防止 JS 精度丢失)
groupBatchId Body String 否 GROUP 产品传;null 或空串视为未指定;非数字返回 600003「团期ID格式错误」;≤0 视为未指定 团期 ID。有效时下单与该团期的改期联动互斥
departureDate Body LocalDate 否 yyyy-MM-dd 出发日期
adultCount Body Integer 否 ≥1,缺省 1 成人数
childCount Body Integer 否 ≥0,缺省 0 儿童数
youngChildCount Body Integer 否 ≥0,缺省 0 小童数
babyCount Body Integer 否 ≥0,缺省 0 幼童数
childNeedBed Body Boolean 否 缺省 false 儿童是否需要床位
tierSeq Body Integer 是 ≥1 档位序号
roomCount Body Integer 否 传则 ≥1 房间数
sharerOpenid Body String 否 ≤64;可传空串;非空时只能含字母、数字、下划线、短横线 分享人 OpenID
customizerId Body Long 否 ≥1 分享人定制师 ID
contactName Body String 是 非空白,≤50 联系人姓名
contactPhone Body String 是 非空白,≤20 联系人电话
remark Body String 否 ≤500 订单备注

本次请求字段零变更。上表为完整字段表,与改前一致。

出参

字段 类型 说明
orderId String 订单 ID。后端为 Long,超出 JS 安全整数范围时序列化为字符串,一律按字符串处理
orderNo String 订单编号,格式为 HL + 年月日时分秒 + 3 位毫秒
groupCode String 4 位团号,订金支付成功时生成;未生成时该字段不出现
groupBatchId String 团期 ID(序列化同 orderId),只有团期订单才出现
productId String 产品 ID(序列化同 orderId)
departureDate LocalDate 出发日期
returnDate LocalDate 返程日期
  • 响应对象带 @JsonInclude(NON_NULL):值为空的字段(如订金支付前的 groupCode)直接不出现,不会以 null 返回。前端按「字段缺失」判空。
  • 本次响应字段零变更。出参与 GET /mp/order/{orderId} 详情接口同构;上表只列标识字段,完整字段见既有详情接口文档。

请求示例

{
  "productId": "1900123456789000001",
  "groupBatchId": "1900123456789000002",
  "departureDate": "2027-01-27",
  "adultCount": 2,
  "childCount": 1,
  "tierSeq": 1,
  "contactName": "林晓梅",
  "contactPhone": "13900001234",
  "remark": "老人同行,希望安排低楼层"
}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "orderId": "1900123456789000003",
    "orderNo": "HL20270127143025001",
    "groupBatchId": "1900123456789000002",
    "productId": "1900123456789000001",
    "departureDate": "2027-01-27",
    "returnDate": "2027-02-01"
  },
  "traceId": null,
  "success": true
}

空数据 / 降级响应

本接口没有空数据形态。

  • 订单服务等待超过 10 秒,或暂时不可达时,返回下方错误响应里的 5xx(文案「服务暂时不可用,请稍后重试」),不会返回半成品数据。
  • 上述错误响应的 HTTP 状态码都是 200,结果看 code。

错误响应

团期下单撞上改期联动,等满 5 秒联动仍未结束(不成单,可以直接重提):

{
  "code": 100503,
  "message": "资源被占用,请稍后重试",
  "data": null,
  "traceId": null,
  "success": false
}

订单服务超过 10 秒没给出结果(订单可能已经生成,先查订单列表再决定是否重提):

{
  "code": 500,
  "message": "服务暂时不可用,请稍后重试",
  "data": null,
  "traceId": null,
  "success": false
}

真的重复提交(上一次下单请求已被受理或仍在处理,不要自动重提):

{
  "code": 100502,
  "message": "请勿重复提交订单",
  "data": null,
  "traceId": null,
  "success": false
}

业务边界

  • 什么时候会等:只有 groupBatchId 解析为正数时,下单才与该团期的改期联动互斥。不带团期的下单不等。

  • 等多久:最多 5 秒,后端常量,前端不可调整。测试服实测一次改期联动占用 41–688 毫秒(12 次),所以多数情况是「慢一点但成单」,100503 只在联动占用超过 5 秒时出现。

  • 100503:不成单,因为等锁失败时创单业务还没开始执行。可以直接重提,不需要任何清理。

    • 重提不会撞 100502。小程序层的防重窗口 5 秒,100503 返回时已过;订单服务层的防重键在 100503 时随失败释放。
  • 500 等 5xx(等待超过 10 秒或订单服务不可达):小程序服务不再自动重发,但订单服务端已开始的那次创单不会中止,可能已经成单。

    • 此时直接重提可能产生两张订单:订单服务层同用户同产品的防重窗口是 10 秒,从原请求开始计时,到 500 返回时已基本过期。(按代码机制推导,测试服未构造过超过 10 秒的场景。)
    • 建议提示「网络繁忙,请到我的订单查看」,先刷新订单列表,确认没有新订单再让用户重提。
  • 100502 现在只表示真的重复提交,有两层窗口:

    • 小程序层:同一用户 5 秒内第二次下单,不分产品。成功下单后 5 秒内再下也算。
    • 订单服务层:同一用户同一产品 10 秒内第二次下单。

    收到时说明前一次请求已被受理或仍在处理,引导用户到订单列表查看,不要自动重提。

  • 100501「下单过于频繁,请稍后再试」:订单服务层按用户限流,每个用户 60 秒内最多 5 次下单请求。既有行为,未变。

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

  1. 按 code 区分错误,不要按 message 判断。100502、100503 和 5xx 的文案相近,处理方式完全不同。
  2. 下单请求的前端超时不要短于 15 秒:服务端最长 10 秒给出结果,另有网关与网络开销。前端先放弃时,用户看不到 100503,后台却可能已成单。
  3. 提交期间禁用提交按钮,直到收到响应。团期下单撞上改期联动时,正常响应也可能慢约 5 秒。
  4. 收到 100503 可以直接重提原请求。
  5. 收到 5xx(code ≥ 500)先刷新订单列表,确认没成单再重提。
  6. 收到 100502 不要自动重提,引导用户到订单列表查看。

五、数据库行为

结果 数据库写入
100503 零写入:等锁失败发生在创单业务开始之前
100502 / 100501 零写入:在进入创单业务前就被拦截
5xx(等待超过 10 秒) 订单服务端那次创单照常提交或失败,与小程序有没有收到结果无关
成功 写入与改前完全一致;本次不涉及任何表结构变更

六、边界行为

  • 两个时限(等锁 5 秒、小程序服务调订单服务超时 10 秒)都是服务端固定值,请求参数无法调整。
  • 本接口与管理端创单复用同一套创单内核,锁判断完全一致。
    • 管理端用 productBatchId 数字。
    • 小程序用 groupBatchId 字符串,两者是同一个 ID。

六.6、修改前后对比

字段级对比

本接口请求、响应字段均零变更,变的只是失败和变慢时的返回。

行为级对比

场景 改前(#8666 上线后、本次之前) 改后
团期下单,没撞上改期联动 正常成单 正常成单,无差异
团期下单,撞上改期联动且联动在 5 秒内结束 约 3.5 秒返回 100502,后台其实已成单 等联动结束后正常成单,响应最多慢约 5 秒
团期下单,联动占用超过 5 秒 约 3.5 秒返回 100502,没有成单 约 5 秒返回 100503,没有成单,可直接重提
任意下单,订单服务处理超过 2 秒 小程序服务约 2 秒超时后自动重发同一请求,用户可能收到 100502 而后台已成单 等到 10 秒;超过 10 秒返回 500,不重发

在 #8666 之前,下单完全不与改期联动互斥。撞上改期时可能按旧出发日成单,且日期与团期永久错位、无人察觉。#8666 堵住了这个窗口,本次修正的是它在小程序链路上的错误码表现。

六.7、影响评估

  • 是否破坏向后兼容:否。请求、响应字段零变更,正常成单路径不变。
  • 前端是否必须同步上线:否。未识别 100503 时展示原始 message 不会白屏。但若前端下单请求的超时短于 15 秒,需要调整,见第四节第 2 条。
  • 前端 workaround 清理点:无。

七、不影响范围

  • 小程序其他订单接口(列表、详情、取消、改单等)调订单服务的等待上限与重试策略未变。
  • 请求、响应字段零变更。
  • 网关路由零变更,无数据库结构变更。

八、测试环境已验证

2026-10-03 测试服部署 hl-mp-service(dev-v3 f4e45c2f1)后实测。做法:用测试 C 端用户直连小程序服务,在自建团期上人为占住改期联动锁。

场景 响应 耗时 成单 订单服务收到的请求
联动占用约 3.5 秒 成功,data 为完整订单详情 约 3.5 秒 1 单 1 次
联动占用约 6 秒 100503「资源被占用,请稍后重试」 约 5 秒 0 1 次
上一行锁释放后间隔 ≥5 秒重提 成功 正常 1 单 1 次
收到 100503 后 0.3 秒内立即重提(锁剩余不足 1 秒) 未返回 100502,等联动结束后成功 未单独计时 1 单 2 次,即两次真实提交,无自动重发
不占锁的常规下单 成功 正常 1 单 1 次
  • 常规下单的响应 data 与 GET /mp/order/{orderId} 的 data 做了字段集比对:61 个字段路径,零差异,二者同为 MpOrderDetailVO。
  • 改前基线是部署前用同一夹具、同一方法测的:
    • 联动占用约 3.5 秒:约 3.5 秒返回 100502,但后台已成单,订单服务收到 2 次。
    • 联动占用约 6 秒:同样返回 100502,未成单。
  • 本轮未构造订单服务超过 10 秒才返回的场景,所以 500 之后可能已成单这一点仍是按代码推导,见业务边界。

十、相关文档

  • 管理端同源改动:changelogs-v2/2026-10/03_8666_产品班期改出发日联动团期与子单日期并新增改期拒绝码-修改接口-管理后台.md(#8666)。改期联动本身的事件与拒绝码以该条为准。
  • 内部转发路径:POST /mp/order/create(hl-mp-service)→ POST /v3/internal/mp/order/create(order-v3)。/v3/internal/** 只供服务间调用,不经网关,前端不可达。
  • 100503 是全仓统一的锁竞争可重试错误码。

关联 / 联系人

链接

  • Issue: #8739(本次)、#8666(引入改期联动锁)
  • PR: #8740、#8738
  • Merge commit: f4e45c2f147eb5e0deec4dbd920e6c82c496ec7b(#8740)、fad5d7814b2d1fb940d740457dbed754e46d03f9(#8738)

联系人

  • 后端负责人: @wx