114 lines
9.4 KiB
Plaintext
114 lines
9.4 KiB
Plaintext
战令结束结算接入说明(2026-10-09)
|
||
|
||
时间契约
|
||
沿用现有 passCheck/read 返回的 time:毫秒级周期起点,结束点为 time + 30 天。
|
||
不把该值改成秒,也不改变已存档 stage.time(毫秒结束点)。周期保留运营配置的
|
||
北京时间起点,不再按云函数宿主本地时区 setHours,也不再由不同接口分别推进30/60天。
|
||
|
||
发布清单(本次只本地实现和测试,尚未部署)
|
||
1. 先发布 passCheckSettlement、passCheckJobs、passCheckUpgrade、passCheck、
|
||
passCheckTime、wx/checkIos、wx/orderPaySig、wx/iosorderPaySig、wx/KeFuInfo。
|
||
三个下单入口必须随 passCheckUpgrade 一起发布,等待异步读取归档中的补购资格。
|
||
passCheckUpgrade 补齐了 POST YAML。
|
||
2. 按 functions/pass-check.trigger.json 创建/更新每分钟触发器,目标 passCheckJobs。
|
||
passCheckJobs 不开放 HTTP 方法;需要现有 PASSCHECKTIME_ID 环境配置。
|
||
每分钟仅用于检查周期和继续未完成的批次;本期扫描完成后不再读取用户表。
|
||
3. 再发布配套客户端。旧客户端的过期进度写入将被拒绝,不能继续按旧方式领上期奖励。
|
||
4. 不清空用户历史。后台仅处理 users,快照迁入独立集合 passCheckSettlements,
|
||
每玩家每期一条文档。users.passSettlementRevision 保留为固定大小的 CAS 计数器。
|
||
每期只完成一轮分页扫描,
|
||
每次触发处理最多100条;进度保存在 passCheckJobCursors。
|
||
请按用户规模评估扫描延迟;玩家请求时同样惰性补建快照,不必等待后台扫到自己。
|
||
|
||
独立集合与无事务一致性
|
||
- passCheckSettlements:_id(账号集合+玩家ID+期末时间)、uid、accountTable、end、
|
||
revision、row。row 完整保留冻结进度、claimed/emptySeen/offer、补购凭据和实际奖励。
|
||
后台仅处理 users;accountTable 用于隔离原接口既有的账号命名空间,不新增 usersAd 扫描。
|
||
- 首次访问自动创建唯一复合索引 {accountTable:1, uid:1, end:1},索引名
|
||
pass_settlement_owner_end;_id 同样是确定性唯一键。云函数需有建索引及读写权限。
|
||
索引创建失败会停止本次请求,不降级成无索引全表查找。该集合不得开放客户端直接写权限。
|
||
- MongoDB 不需要支持事务。users 中仅暂存最多一条 passSettlementPending:
|
||
{revision,row}。资源余额变更、固定大小的 revision 和待归档凭据在一次 updateOne
|
||
中原子保存;归档成功后才清除该临时字段,成功后的 users 不保存历史结算字典。
|
||
- 所有结算写入先恢复待归档记录;未同步成功前不接受下一笔结算写入。若余额已入账后
|
||
归档或回包失败,重试只会同步既有凭据、返回已领取结果,不会重新增加余额。
|
||
归档按 revision 单调更新,清除临时字段时核对其 revision,防止迟到请求覆盖新状态。
|
||
不依赖超时锁保证发奖幂等;定时任务的租约只保护扫描进度。
|
||
- 旧 users.passSettlements 按期逐条迁移。每次先原子转存到待归档字段并移除对应旧键,
|
||
再写独立集合;最后一个旧键迁移后移除整个旧字段。任意中断时数据仍在原字段、
|
||
单条待归档字段或独立集合中,不直接清空未保全的历史数据。已领取、永久放弃和补购
|
||
状态保持不变;旧记录与归档发生内容冲突时停止并返回409,保留两份供核对。
|
||
- freezeUser 返回对象上的 passSettlements 只是为了兼容内部逻辑临时组装的内存视图,
|
||
不会把该字典写回 users。客户端协议保持原样,仍按最新奖励配置计算数量。
|
||
- 本次只迁移结算字段,不清理 passCheckUpgrade 或订单历史,也不设置自动过期删除;
|
||
未领取奖励和支付收据均保留。
|
||
|
||
按期扫描与旧任务升级
|
||
- 当前全局周期起点同时是上一期结束点,以该毫秒时间戳标识扫描期。
|
||
即使在线接口先推进了全局周期,后台仍会对比自己的 periodEnd,启动新一期扫描。
|
||
- 进度键改为 archive:users;保存 periodEnd、after、completed、
|
||
completedAt、revision、leaseUntil。仅使用已有集合的 _id 索引,无需手动初始化。
|
||
保留旧 users/usersAd、season:users 等游标但不再访问;新键不存在时从头补扫一次,
|
||
确保旧版已经扫完的用户也能迁移。后续使用 archive:users 断点续扫。
|
||
任务不访问 usersAd 集合及其历史进度记录。
|
||
此后只有全局周期推进才开启新一轮;配置的起点还在未来时不扫描。
|
||
- 每批成功后推进游标,不足100条时标记完成;恰好整批时下一次空页确认完成。
|
||
完成后每次触发仅读取周期配置和 archive:users 进度文档,不扫描用户,
|
||
不反复更新游标;云函数每分钟的触发次数本身未减少。
|
||
- 每批取得5分钟租约,并用 revision 比较更新防止重叠执行或旧执行覆盖新进度。
|
||
批次失败保留起始游标、释放租约,下次重试;进程直接退出时租约到期后恢复。
|
||
失败重试或租约超时接管可能重复读取该批,但已有快照不重复生成,也不自动发奖。
|
||
- 跨期仍未扫完时先续完旧扫描,再开启最新一期。停机错过多期时无需为每个中间期
|
||
重扫全服:freezeUser 一次补齐该玩家存档中所有可验证的到期记录。
|
||
扫描完成后新增或导入的历史玩家记录,由其在线请求补建,或在下一期扫描时补齐。
|
||
- 已部署旧版时,安排维护窗口,先备份 users 和订单、暂停旧定时任务及战令写入/补购
|
||
入口,等待旧请求退出;完整发布本页清单后再恢复入口和定时任务。严禁新旧结算写入
|
||
逻辑混跑。cron 仍为 * * * * *,配套客户端无需因本次存储调整而修改。
|
||
- 不可直接回滚到仍读写 users.passSettlements 的旧函数:它可能重建已领取记录。
|
||
如需回滚,应停止战令写入并核对归档及待同步凭据,制定数据回迁方案。
|
||
|
||
协议
|
||
POST passCheckSettlement,使用现有 uid/token/gameName 鉴权。
|
||
read:返回 rows(按结束时间升序)、resources、serverTime。
|
||
empty_seen + end:图2实际展示后标记该期已提示。
|
||
offer_shown + end + offerToken:图1实际展示后消耗唯一展示机会;仅原令牌/登录会话
|
||
可重试确认。令牌不在 read 中返回;进程关闭后不可恢复该购买窗口。
|
||
decline + end:永久放弃该期机会,不影响已支付订单的补发。
|
||
claim + end + rewards + claimFlags:领取客户端按最新配置计算的已解锁未领奖励。
|
||
purchase_claim 另加 outTradeNo:上期18元订单补发已解锁付费奖励。
|
||
rewards 为合并后的 coin/freeze/hammer/magic/infinite_health,体力数量单位为秒。
|
||
claimFlags 仅更新实际领取的 free/passCheck 索引为0,不修改冻结经验或等级。
|
||
|
||
服务端不保存奖励配置或版本、不计算应发奖励数量。按已确认的客户端可信方案,
|
||
只检查类型/正整数、归属、支付状态和收据。此方案防重复领取,但不能防篡改客户端
|
||
伪造奖励数量;这不是服务端权威发奖方案。
|
||
|
||
一致性
|
||
到期只冻结进度、购买档位、领取标志,不给离线玩家入账。
|
||
普通进度更新用数据库 $$NOW 截止条件;冻结同时 CAS 所有进度输入。
|
||
领取资源增量与单条待归档收据在同一用户文档原子写入,订单状态更新可幂等补齐。
|
||
已支付的期内订单延迟恢复时,仅接受冻结进度及订单对应权益,不接受客户端替换
|
||
过期进度。领取掩码保留,30元的20点经验/3000金币仍沿用已有权益逻辑。
|
||
同一期第二笔补购支付不二次发奖,订单标记 passReview=duplicate_post_season_payment,
|
||
需人工退款处理,不自动退款。
|
||
|
||
验证
|
||
Node 24:node --test laf-cloud/tests/pass-check-settlement.test.mjs(27项通过)。
|
||
覆盖完成后零用户扫描/零写入、分页、新周期、空集合/整批边界、失败重试、旧游标升级、
|
||
跨期续跑、租约超时接管与旧执行防回退、在线补建、未来周期配置、完全不访问 usersAd
|
||
及其旧进度记录;保留原发奖幂等测试。另覆盖40期迁移、迁移中断、归档失败/丢回包、
|
||
临时字段清除失败、迟到同步防回退、延迟升级及补购恢复、玩家隔离和并发唯一记录。
|
||
配套客户端 tools/test-battle-pass-settlement.cjs 覆盖奖励表、UI关闭=领取、
|
||
失败重试、确认弹窗、优先队列、多期顺序和支付幂等。
|
||
payment-profile.test.mjs 的8项通过;payment-routing.test.mjs、rookie-gift.test.mjs
|
||
在导入阶段失败:goldMiner/config 缺少 paymentProductId 导出,未修改该模块。
|
||
|
||
上线前真机验收
|
||
Android、原生iOS支付、客服iOS支付分别验证成功/取消/延迟回调/杀进程恢复。
|
||
跨截止时刻验证已解锁未领范围、点击X领取、奖励动画后补购、永久放弃。
|
||
断网/重复点击/跨设备重试验证资源只入账一次。停留在图1时可重试失败支付,
|
||
重新登录不恢复该期图1;已支付订单仍可从原有登录订单补发入口恢复。
|
||
本地模拟数据库和Cocos视觉预览不替代上述真实支付及云端验收。
|
||
独立集合上线另需验证:唯一索引实际创建成功;人为阻断归档写入后仅余额和单条待同步
|
||
凭据落库,恢复后归档完成且不重复发奖;旧快照迁移后用户字典消失、领取状态不变。
|