server/laf-cloud/docs/pass-check-settlement.txt

114 lines
9.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

战令结束结算接入说明(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视觉预览不替代上述真实支付及云端验收。
独立集合上线另需验证:唯一索引实际创建成功;人为阻断归档写入后仅余额和单条待同步
凭据落库,恢复后归档完成且不重复发奖;旧快照迁移后用户字典消失、领取状态不变。