4.4 KiB
4.4 KiB
送礼连击 V2 协议
边界
V2 只改变客户端封批、可靠重试和结算结果重放,不改变房间状态 owner:
- Flutter 立即播放连击反馈,第一批立即请求,后续点击按远程窗口聚合。
- HTTP 仍是账务入口;
room-service的 Room Cell 串行提交房间状态。 wallet-service负责扣费,lucky-gift-service负责逐份独立抽奖,room-service只编排持久化 Saga。- V1 路由和顶层响应字段只为已发布的旧客户端保留;当前 Flutter 固定调用 V2,不做 V1 降级。
HTTP 契约
新客户端调用:
POST /api/v2/rooms/gift/send
请求沿用 V1 字段,并要求:
{
"room_id": "room-id",
"command_id": "stable-combo-session_b1",
"combo_session_id": "stable-combo-session",
"batch_seq": 1,
"target_type": "user",
"target_user_ids": [1001, 1002],
"gift_id": "gift-id",
"gift_count": 20,
"pool_id": "optional-lucky-pool"
}
command_id 是唯一财务幂等键。超时、429 和临时 5xx 必须复用同一请求体与同一 command_id;combo_session_id + batch_seq 只用于客户端批次顺序和审计。当前 Flutter 不在 404 或旧响应下改调 V1,发布前必须先保证 V2 路由可用。
响应继续返回 V1 顶层的 billing_receipt_id、coin_balance_after、lucky_gift(s)、batch_display 等字段,同时增加 v2:
{
"billing_receipt_id": "legacy-compatible-receipt",
"coin_balance_after": 9000,
"v2": {
"api_version": 2,
"command_id": "stable-combo-session_b1",
"combo_session_id": "stable-combo-session",
"batch_seq": 1,
"idempotent_replay": false,
"committed_room_version": 123,
"billing_receipt_id": "legacy-compatible-receipt",
"coin_balance_after": 9000,
"balance_version": 456,
"settled_gift_count": 20,
"settled_target_user_ids": [1001, 1002],
"lucky_hits": [],
"operation_status": "committed"
}
}
相同 command_id 的重试返回首次提交的同一账务回执、余额版本、实际目标、幸运结果和批次展示,仅把 idempotent_replay 置为 true。历史 V1 command log 没有 typed 结果时保持原有 snapshot-only 行为,不伪造结算结果。
客户端封批规则
礼物面板响应的 combo_config 控制客户端策略:
enabled:紧急关闭微批;关闭后仍调用 V2,只是不再聚合连续点击。api_version:服务端契约版本标记,当前 Flutter 只接受 V2,不用它选择 V1 入口。window_ms:后续点击固定封批窗口,默认 300ms。max_gift_count_per_batch:单目标数量上限,最大 999。max_gift_units_per_batch:gift_count * 去重收礼人数上限,最大 5000。max_in_flight:最多 2 个 HTTP 批次在途。max_pending_batches:本地有界队列上限。retry_max_attempts、retry_base_delay_ms:可靠重试上限和指数退避基数;429 优先遵守Retry-After。rollout_basis_points:按app_code + user_id稳定分桶,0 到 10000;只灰度微批策略,不改变 V2 HTTP 入口。
后台通过以下 app-scoped 接口读取和全量替换配置:
GET /admin/app-config/gift-combo
PUT /admin/app-config/gift-combo
服务端在 gateway、room、wallet、lucky 四层都强制校验 gift_count <= 999、总 gift units <= 5000 和幂等键长度。远程配置只能收紧客户端行为,不能提高 owner 上限。
上线顺序
- 先执行
services/room-service/deploy/mysql/migrations/002_gift_operation_v2.sql,再滚动发布 protobuf、wallet、lucky、room、gateway,确认 V2 可用后发布当前 Flutter;已发布的旧 Flutter 继续走服务端 V1。 - 首次上线把
rollout_basis_points设为 0,验证 V2 单批发送、重复command_id重放和 Gift Saga 恢复指标;该值不会让当前 Flutter 回退 V1。 - 按 App 从小流量提高微批灰度;异常时把
enabled=false或灰度归零,客户端仍使用 V2 单批发送。 - MQ 先保持
wallet_event_tag_mode=legacy、room_event_tag_mode=legacy。确认所有兼容 consumer 已上线并排空存量后,再分别切为event_type;不要在同一批发布中同时切 producer 和删除 legacy selector。
数据库迁移、服务发布、Flutter 微批灰度和 MQ Tag 切换是四个独立开关。任何一步都不能用“客户端已限流”替代 owner 幂等、Saga 恢复或 Broker 侧过滤。