30 KiB
节日活动交互、Rust 服务端与上线事务规划
记录日期:2026-10-21。
状态:设计草案,供产品选择与后续实施使用;本轮仅编写文档。 本文没有表示 Rust 服务、同步协议、活动表或活动命令已经实现。 所有默认值均为建议,尚未进行负载、断网及真实 QQ 群验证。
1. 现状依据与设计边界
- 用户交接:农场已有播种、收获、仓库与偷菜等基础功能。 151 项回归及后续 2 项相关测试的通过情况来自用户交接,本轮未重跑。
- 现有文档
stealing.md描述 SQLite 事务、重放收据及版本 4;18-web-panel-and-data-directory.md描述本地farm.sqlite3。 本轮阅读文档,没有据此宣称已核验当前源码及生产数据库。 AGENTS.md要求数据库保存权威状态,应用服务拥有事务边界, 框架对象止于接入层;不修改 legacy 参考基线。03-business-rules.md的身份隔离、幂等及外部资产设计属于已有建议, 接入活动前仍需与实际身份模型、仓储接口及消息 ID 核对。- 本轮开始时
git status --short无输出;与此前未提交的交接状态不同, 不推断此前改动如何处理,也不恢复、覆盖或提交其他内容。 - Rust 用于新增服务端,不将现有 Python 农场整体重写为 Rust。 服务端建议独立仓库;本轮不创建服务工程或依赖占位文件。
2. 先决定服务端负责什么
| 方案 | Rust 服务负责 | 农场负责 | 主要代价 |
|---|---|---|---|
| A:活动发布中心,建议首期 | 配置、排期、发布、停用、同步状态 | 玩家进度、活动币、兑换、实际发奖 | 无全局共享余额;信任各部署 |
| B:集中活动账本 | A 的职责,加进度、活动币、限购与兑换单 | 上报事件、接收并入库奖励 | 网络依赖、事件防重、跨库交付与对账 |
| C:全部农场中心化 | 农场与活动全部权威业务 | QQ 指令与展示 | 数据迁移和可用性改造范围大 |
建议先做 A:上架活动不再要求发布插件,而玩家资产仍在原数据库事务内 变化。各机器人部署的活动资产独立,不宣称跨机器人共用,也不支持 全服限量兑换。若明确需要这两项能力,再采用 B。
信任边界:A 中部署管理员能够修改自己的 SQLite;服务端签名只能保护 发布配置,不能证明玩家行为真实。面向不受信任的第三方部署发放全服 稀缺奖励时,应重新评估 B 及事件可信来源,不能只接受客户端报来的数量。
3. 文字交互方案留档
3.1 五种可选方式
| 方案 | 示例 | 优点 | 限制 |
|---|---|---|---|
| 固定活动入口 | 农场活动、活动任务 |
学一次长期使用 | 多活动需明确目标 |
| 节日短名 | 万圣商店、端午任务 |
有主题感,便于并存 | 每期需展示入口 |
| 商品短编号 | 活动兑换 W1 |
不用输入复杂商品名 | 编号必须稳定 |
| 引用消息菜单 | 回复菜单发送 2 |
新手不用背指令 | 需验证 QQ 引用消息能力 |
| 融入日常操作 | 收获额外掉落糖果 | 参与成本低 | 提示需节制,掉落需事务化 |
建议组合:固定入口 + 商品编号 + 日常玩法;节日短名作为快捷入口。 引用菜单为后续增强,不作为首期依赖,不监听群聊中的裸数字。
3.2 推荐命令
| 命令 | 行为 |
|---|---|
农场活动 |
列出可见活动、主活动进度和时间 |
活动任务 |
查看主活动任务 |
活动领奖 |
一次领取主活动全部已完成且未领取的任务奖励 |
活动商店 |
查看主活动商店、余额、限购 |
活动兑换 W1 |
兑换指定商品 1 份 |
活动兑换 W2 3 |
兑换指定商品 3 份 |
万圣商店 |
明确查看万圣活动 |
万圣兑换 W1 |
明确操作万圣活动 |
规则:
- 主活动由发布配置指定,同一部署同一时刻至多一个;不由玩家上次 查看菜单决定。无主活动且存在多个候选时,仅提示可复制的明确指令。
- 商品编号在展示范围内唯一并绑定某期活动;不能只用每页第几项。
例如本期为
W26-1,下一年不能把同一编号复用给另一件商品。 示例W1是简写演示,正式编号策略需在首期冻结。 - 通用兑换可按唯一商品编号直接定位活动,不必重复活动名。
- 批量兑换必须全部满足余额和限购才成功;不静默缩减数量。
- 失败说明原因及下一条可执行指令;查询不发奖,消息发送失败不重复交易。
- 进入补兑期时,菜单显示“掉落已结束,兑换截止:北京时间某日某时”。
- 活动菜单默认文字;普通日常操作只在确有掉落、完成任务等变化时 附带一行提示,不每次发送完整活动广告。
3.3 用户可见示例
【万圣南瓜夜】
掉落截止:11 月 1 日 00:00(北京时间)
兑换截止:11 月 4 日 00:00(北京时间)
糖果:36;任务奖励:1 项可领取
收获作物有机会获得糖果。
查看任务:活动任务
领取奖励:活动领奖
查看商店:活动商店
W26-1 南瓜灯装饰 20 糖果 本期剩余 1
兑换:活动兑换 W26-1
上述日期和奖励仅为示例。没有实际可用装饰系统前,不上架装饰奖励; 首期可用已有种子、作物或内部货币,避免创建无效道具。
4. 农场如何知道活动上架了
4.1 推荐:主动拉取,通知只作加速
sequenceDiagram
participant O as 运营者
participant R as Rust 发布中心
participant D as 服务端数据库
participant F as 农场插件
participant L as 本地 SQLite
O->>R: 校验并发布活动
R->>D: 同一事务保存不可变版本和发布序号
D-->>R: 提交成功
F->>R: 启动或定期查询目录
R-->>F: 当前完整目录、版本和有效期
F->>F: 校验兼容性、范围及奖励能力
F->>L: 事务安装快照并切换生效指针
F->>R: 上报已应用序号或失败原因
Note over F,L: 实际开关由时间与状态判定,不依赖定时器准时触发
建议首期:启动同步一次,随后每 60 秒加随机抖动拉取;玩家访问活动 且快照过旧时触发一次共享刷新,避免每条消息各发一个请求。 网络请求不占用 SQLite 写事务,设置短超时并指数退避。
发布成功只表示服务端已提交;应分别展示“已发布、待客户端应用、 已应用、被拒绝、离线”。没有客户端确认时,不能显示全服上线成功。
4.2 目录响应与一致性
首期直接返回作用域内完整目录,规模小时比增量协议更容易正确处理删除。 目录至少覆盖预告、进行中、补兑和停用记录,不只返回正在进行的活动。
| 字段 | 实际用途 |
|---|---|
catalog_revision |
单调递增的发布序号,拒绝乱序响应覆盖新状态 |
server_time |
检查本机时钟偏差,辅助解释时间错误 |
valid_until |
允许进行活动资产操作的快照授权截止时间 |
events |
该部署当前可见的完整活动及不可变配置版本 |
revoked_instances |
显式停用的活动实例,防止旧缓存继续启用 |
传输使用 HTTPS,部署身份由服务端凭据绑定,不能相信请求里的任意
deployment_id。支持 ETag/条件请求以降低开销,但 304 不自动延长
资产操作授权:有效期要通过可验证的新元数据或一次完整响应续期。
目录内容哈希用于检测损坏;若允许离线分发配置包,再加入签名与密钥轮换。
客户端先验证整个目录,再事务保存快照、撤销信息及生效序号;失败则 保留上个完整版本并上报错误,不先更新序号再下载失败。 目录为空表示确实没有活动,网络失败绝不能解释成空目录并清库。
离线展示可使用旧快照并标明更新时间;活动掉落、领奖和兑换必须同时 满足业务时间及授权有效期。建议首期授权最多 5 分钟,过期则暂停活动 资产操作,基础播种收获继续,且回复明确说明活动暂不可用。 这意味着断网跨过授权期限时不补发活动掉落;该取舍需在上线说明告知。
定时轮询加本地授权具有停用延迟:健康网络通常在一个轮询周期内, 断网时最多延续剩余授权时间,无法承诺瞬时全局停服。 若业务要求每笔兑换立即服从紧急停用,必须每笔在线授权或采用方案 B。
4.3 是否需要 WebSocket、SSE、Webhook
- 首期不需要长连接,轮询能穿过机器人所在机器的 NAT。
- 后期可加 SSE,通知仅携带“目录可能变化”,客户端仍重新拉取。 断线后恢复轮询,不把消息送达当作业务提交或客户端已应用。
- Webhook 需要插件暴露可访问入口,不作为默认接入方式。
- PostgreSQL
LISTEN/NOTIFY可辅助唤醒服务内部工作者;它不是面向 离线机器人的持久同步协议,发布记录仍必须入表。
PostgreSQL 官方说明通知面向已监听连接,事务中的通知在提交后交付; 因此本设计将数据库记录作为依据,通知只作提示。 来源:PostgreSQL NOTIFY。
5. 活动生命周期与时间
区分运营状态和按时间计算的玩家阶段,不存储互相矛盾的重复状态。
运营状态:草稿、已发布、暂停、撤销、归档。 玩家阶段由已发布状态和时间计算:
| 阶段 | 时间范围 | 允许行为 |
|---|---|---|
| 预告 | visible_at <= now < starts_at |
查看规则,不计进度、不领奖 |
| 进行中 | starts_at <= now < ends_at |
计进度、掉落、领奖和兑换 |
| 补兑期 | ends_at <= now < redeem_until |
只领取此前完成任务和兑换 |
| 已结束 | now >= redeem_until |
只查历史,不新建奖励交易 |
时间均存 UTC,文案按 Asia/Shanghai 展示;每日任务与限购按北京时间 日期分桶。采用左闭右开区间,恰好等于截止时间即不再接受新操作。
暂停:先统一暂停活动资产写入,保留查询;必要时恢复。 撤销:永久停止本期新操作,进入问题处理,不删除账本。 已经提交的奖励不因撤销自动收回;补偿与追缴必须形成独立审计操作。
计划排期预先下发到插件,本地在时间边界自然切换;定时工作者迟到不会 让活动多开放一天。重启后按当前时间重算,不依赖内存倒计时。 检测到明显时钟异常时停止活动资产操作并告警,不用旧授权无限续命。
6. Rust 服务端最小组成
建议一个服务进程加一个 PostgreSQL,先不引入 Redis、消息中间件或微服务。
| 模块 | 职责 |
|---|---|
| 管理 API | 草稿、校验、发布、暂停、撤销、查询发布情况 |
| 配置校验 | 时间、整数范围、商品编号、命令别名、规则与奖励能力 |
| 发布应用服务 | 比较预期版本、事务提交、生成发布审计 |
| 同步 API | 按部署返回目录、授予短期有效期、接收应用结果 |
| 后台工作者 | 扫描待处理维护任务、归档、清理和失败重试 |
| 存储与日志 | SQL 事务、迁移、备份、结构化文件日志和指标 |
技术候选为 Tokio + Axum + SQLx + PostgreSQL;实现时再锁定版本和最低 Rust 版本。Axum 用于 HTTP 路由与请求处理,SQLx 用于数据库事务; 库的回滚能力不能替代应用自行设计幂等和事务边界。 参考:Axum、 SQLx Transaction。
首期允许使用管理 CLI 调用同一管理服务,不必先建设运营网页。 活动配置只允许受支持的声明式规则,不下发 Python/Rust 脚本、SQL、 模板执行表达式或可执行插件。不支持的新玩法需先升级农场能力。
7. 数据设计:每个概念必须参与业务
7.1 服务端发布数据(方案 A)
| 概念 | 必要内容及用途 |
|---|---|
| 活动实例 | instance_id 标识某年某期;名称、别名用于展示与解析 |
| 配置版本 | revision、规则、商品、时间、能力要求、哈希;发布后不可变 |
| 发布记录 | 当前版本、运营状态、目标部署、主活动标记、发布序号 |
| 部署应用结果 | 部署标识、已应用序号、能力集合、最近在线时间、失败码 |
| 操作审计 | 管理员、操作、前后版本、原因、时间;支持故障追溯 |
同一节日每年创建新实例,不修改去年实例来重复开服。 发布时检测同一作用域的主活动时间重叠、别名冲突和商品短编号冲突。 目标名单变更也增加发布序号;被移出范围的客户端必须收到撤销或完整 目录移除语义,不能继续使用无限期缓存。
7.2 农场本地数据(方案 A)
| 概念 | 必要内容及用途 |
|---|---|
| 活动快照 | 实例、版本、授权截止、配置正文;重启可恢复且可追溯 |
| 活动账户 | 玩家作用域、实例、余额;防止跨期花币 |
| 任务进度 | 玩家、实例、任务、日期桶、进度;永久任务不用日期桶 |
| 奖励领取记录 | 玩家、实例、任务、日期桶;唯一约束阻止重复领奖 |
| 兑换累计 | 玩家、实例、商品、限购周期桶、已兑换数量;事务限购 |
| 活动账本与收据 | 操作标识、请求摘要、版本、增减额、奖励结果、时间 |
| 日常行为去重 | 原业务操作与活动、规则的关联;避免重放重复掉落 |
玩家键复用实际农场身份范围,不只保存一个 QQ 号;实施时核对机器人、 平台与共享范围。余额和库存只存整数,明确上限并校验乘法溢出。 若已有账本和操作收据能表达这些用途,就扩展复用,不平行创建重复表。
不为首期添加无业务用途的排行榜、跨服积分、全服库存、邮件状态等字段。 快照版本用于解释交易,不能靠“当前最新配置”重算历史收据。
8. 发布与版本切换事务
8.1 上架步骤
- 运营创建草稿,设定活动期、兑换期、范围、任务和奖励。
- 校验时间关系、已有物品 ID、计量单位、上限、编号和能力要求。
- 在测试部署预演规则,确认菜单中每条指令可执行。
- 管理请求携带幂等键和预期版本;同键不同参数拒绝。
- 在一个服务端事务内生成不可变配置版本、更新发布指针和目录序号、 写入操作审计;失败整体回滚。
- 提交后才响应发布成功。若以后加入可靠推送任务,其待发送记录也在 同一事务写入;不要数据库成功后仅在内存里安排推送。
- 插件获取目录并校验,在本地事务中安装版本;上报已应用序号。
- 观察目标部署应用率、错误和时间,再扩大范围。
管理并发修改采用版本条件更新;两名管理员基于同一旧版本发布,至多 一个成功,另一个重新读取后操作。不能用最后写入覆盖来消除冲突。
8.2 热更新限制
- 文案可以新版本发布;已接受交易始终按其绑定版本结算。
- 活动币归属、任务语义和商品身份不在进行中重新定义。
- 首期建议活动开始后冻结价格、奖励、限购及掉落规则,避免旧快照 在授权期内继续成交造成不公平;调整通过暂停、等待旧授权耗尽、 发新版本、确认部署应用后恢复完成。
- 严重错误通过新发布序号回退到已知配置,不降低序号,不删除已发生交易。
- 本地交易对快照生效指针和授权有效期在写事务中检查;与同步切换 串行化,不能在事务外读到旧配置后无限期继续写资产。
9. 方案 A:本地活动交易
9.1 收获掉落和任务进度
一次收获事务中:
- 查原操作收据;已处理则返回原结果,不再次抽奖。
- 读取活动快照,检查时间、范围、能力和授权;判定时刻在业务锁取得后 采样,不能沿用排队前的旧时间。
- 完成原有收获计算与状态更新。
- 对符合条件的本次实际收获计算活动掉落,更新余额及任务进度。
- 写入行为去重、活动流水及原操作完整收据,一起提交。
活动停用或授权失效属于正常“不参与活动”,不阻塞基础收获;活动 数据库写失败属于事务失败,不能吞掉异常后提交一半结果。 随机结果记录在已提交收据中。若事务回滚,重新计算不产生已到账的重复奖。 不默认让偷来的作物也触发收获掉落,以免改变现有偷菜事务和经济平衡; 如要支持,单独定义触发类型、计量方式并验证。
9.2 任务领奖
在一个事务内检查阶段、已完成进度和领取唯一约束,写领取记录、增加 奖励、写流水和收据,再提交。全部领取以事务内实际可领取集合为准, 并发请求最多领取一次。只查看任务不标记领取。
9.3 商店兑换
BEGIN
查幂等键与请求摘要,已成功则返回原收据
校验快照、授权、时间、商品与正整数数量
条件扣活动币:余额 >= 总价
条件更新限购累计:已购 + 本次 <= 上限
向现有种子/作物/内部货币仓储增加奖励
写活动流水和兑换收据
COMMIT
提交后回复 QQ 消息
余额不足、限购失败或入库失败时整体回滚,不能只扣币。 任何底层仓储方法不能自行提交。网络与绘图不放进事务。 请求幂等键包含部署、机器人、平台、消息标识与动作命名空间;同键不同 参数拒绝。没有可靠消息 ID 时,需要持久化操作令牌,不能用每次新 UUID。
超时未知结果先查收据,不推断失败后再次扣款;已成功收据的查询不受 活动截止限制。永久奖励留在正常仓库,不能随活动账户清理一并删除。 首期不直接兑换真寻外部金币,以免重新引入跨库原子性问题。
10. 方案 B:若以后集中管理活动币
只有需要跨部署共用余额或全服库存时再实施;不能和 A 同时保留两个 可写活动余额。迁移必须暂停入口、结清待办、核对余额并切换唯一权威源。
10.1 日常事件可靠上报
- 农场在原收获事务中写业务结果和待上报事件(outbox),提交后发送。
- 服务端按部署和事件 ID 去重;验证已登记部署、规则、玩家范围和时间。
- 服务端同一事务写接收记录、更新进度/活动币、写账本。
- 客户端仅在收到可查询的成功结果后确认事件已交付;超时重试同 ID。
- 明确迟到事件政策:建议最多接受截止前已发生且在宽限期内收到的事件; 事件时间只能来自受信部署,越过宽限期进入核查,不悄悄改变历史结算。
- 未到账进度显示“待同步”,不能拿尚未服务端确认的余额兑换。
10.2 中心扣币、农场入库不是一个事务
- 服务端在一个事务内校验余额与限购,扣币、创建唯一奖励单和交付任务。
- 农场轮询领取属于本部署的待交付奖励单,或用兑换响应取得该单。
- 农场在一个本地事务内按
grant_id去重、奖励入库、写入库收据。 - 农场提交后确认,服务端把奖励单标记已交付。
- 确认丢失则重发同一奖励单,农场返回已有收据,不二次入库。
玩家看到“兑换已受理,奖励待到账”,到账后才报告已入库。 这里保证的是重试与去重后业务效果一次,不承诺网络只传一次。 待交付任务以数据库为准,多工作者用数据库锁或租约认领并恢复超时任务。
超时不能自动退款。 本地可能已经入库,只是确认丢失。 退款需先通过本地持久化终态证明奖励未发放,并将该单永久标记为取消、 拒绝后续交付;无法建立此屏障则保持待核对,不同时退款和重发。 活动结束后仍交付截止前已受理奖励,不能清除尚未确认的交付单。
11. 如何清理过期活动
“不再展示”“停止写入”“兑换结束”“数据删除”是四个不同动作。 建议自动关闭、延后归档、受控删除,而非到点整表删除。
11.1 分阶段策略
| 时刻/条件 | 动作 | 保留内容 |
|---|---|---|
| 到掉落截止 | 停止新掉落和任务计数,进入补兑 | 余额、领奖资格、商店、流水 |
| 到兑换截止 | 停止新领奖和兑换,移出常用菜单 | 历史收据、旧配置、待核对操作 |
| 在途事务排空后 | 生成结算摘要;将剩余活动币记为过期 | 过期流水、总额、审计依据 |
| 建议结束后 30 天 | 归档活动,历史只读 | 配置与关键资产账本 |
| 满足保留策略后 | 分批删除可重建缓存和不再需要的明细 | 防重依据、待办、永久奖励 |
首期建议剩余活动币过期失效,不自动换基础币;这属于待确认的产品规则, 必须在活动开始前公示。若以后支持自动折算,按玩家生成唯一结算操作, 折算发奖和余额消耗同事务完成,不能靠重新扫描重复发放。
11.2 并发与崩溃恢复
- 截止判定在交易里执行,不靠清理任务更新一个布尔值后才停止。
- 对同一活动账户的兑换与过期结算串行化;取得锁后再次检查阶段。 截止前已受理的事务可以完成,清理等待它们完成,不抢先清余额。
- 维护任务保存活动、阶段、游标、重试次数、最近错误;这些字段用于 断点续跑和告警。多实例服务认领任务时使用数据库锁/租约。
- 每批小事务提交,不用一个长事务扫描所有玩家。
- 每个账户的过期结算有唯一操作标识;崩溃重跑返回既有结果。
- B 方案须等迟到事件窗口关闭、待交付奖励和退款核对完成后再结算; 不能因已到日历上的归档日期就删除尚未解决的数据。
11.3 可以删什么,不能删什么
可以优先清理:旧菜单缓存、可重建展示快照、超过排障窗口的同步诊断。 未发布草稿可以按管理保留策略删除。
不能直接删:永久种子/作物/货币、未交付奖励、待对账交易、有效幂等依据、 被流水引用的规则版本。旧物品若已入仓,正常目录仍要能解释其 ID; 活动下架不能删除仍在使用的物品定义。
关键账本建议先按至少 180 天规划,再根据体量、隐私和运维需求确认; 该天数不是法律要求或既有承诺。幂等记录保留时间必须覆盖消息重放和 任务重试窗口。无法给重放窗口设上限时,保留紧凑的防重摘要,或永久 封存实例并拒绝它的新事件,不能只靠“清过了”防止重复发奖。
首期不开放活动硬删除接口。将来删除需提供预览数量、备份、引用检查、 操作审计及恢复演练。清理工作者无管理权限去删除整个农场数据库。
12. API 草案(首期 A)
以下是接口职责,不是已实现路由;具体 JSON 与错误码在开发设计中冻结。
| 接口 | 作用及事务要求 |
|---|---|
POST /admin/events |
创建草稿 |
POST /admin/events/{id}/validate |
校验草稿及目标能力,不上架 |
POST /admin/events/{id}/publish |
幂等发布;预期版本冲突明确返回 |
POST /admin/events/{id}/pause |
暂停并增加目录序号 |
POST /admin/events/{id}/revoke |
撤销并保留审计与历史 |
GET /admin/events/{id}/rollout |
查询目标部署的应用情况 |
GET /v1/event-catalog |
按已认证部署取得完整目录 |
POST /v1/catalog-ack |
上报应用序号、能力和失败原因 |
管理身份与插件身份分离,插件不能发布活动;限流、请求体大小和操作 数量有上限。客户端上报的版本确认只证明安装,不证明玩家奖励已正确到账。 A 不开放远程“给玩家改余额”接口,避免产生第二个资产写入口。
13. 上线与运营事务清单
13.1 首次部署 Rust 服务
- 确定域名、HTTPS、访问凭据、目标部署范围和备份位置。
- 建立数据库迁移及恢复流程,演练空库启动和失败回滚。
- 先部署兼容旧插件的服务,新服务不要求旧插件立即支持活动。
- 再发布带活动能力的插件;默认活动入口无可用配置时正常提示。
- 校验服务身份、目录拉取、授权到期和撤销机制。
- 在测试群演练完整活动生命周期,不能只检查管理 API 返回成功。
13.2 每次活动上架
- 先创建实例和草稿,核对时间、奖励可用性、经济产出和指令冲突。
- 预告阶段验证目标部署已应用;能力不足的部署显示未覆盖,不强行启用。
- 建议先一个测试部署,再小范围,再全量;发布范围由服务端确定。
- 观察活动指令失败率、同步滞后、兑换回滚、掉落总量和余额异常。
- 正式开始前备份;上线后抽查实际玩家操作、账本与库存结果一致。
- 本设计首期只在用户查询和正常操作中提示,不默认向所有 QQ 群群发公告。
13.3 日常巡检与告警
结构化文件日志记录:操作关联 ID、实例与版本、部署匿名标识、耗时、 阶段、错误码;不记录凭据、完整 QQ 事件或真实玩家信息。 业务账本可保存关联所需玩家键,但按最小权限访问,不能代替普通日志脱敏。
关键告警:目录同步超过授权窗口、客户端版本拒绝、兑换事务失败、 结算任务积压、重复事件激增、时钟异常;B 额外监控未交付奖励和对账单。 服务就绪检查涵盖数据库可用及迁移兼容,不只检查进程是否存在。
13.4 故障与回滚
| 故障 | 处理 |
|---|---|
| Rust 服务不可用 | 基础农场继续;授权过期后暂停活动资产操作 |
| 目录配置无效 | 拒绝整份更新,保留旧快照直至授权到期,上报原因 |
| 插件不识别玩法或奖励 | 标记该部署未应用,不加载一半规则 |
| 错价或异常产出 | 暂停,等待旧授权耗尽,核账,再发布修正版 |
| QQ 回复失败 | 查原收据再回复,不能重复扣币或发奖 |
| 清理任务中断 | 从游标与唯一结算记录恢复,不整表重置 |
| 新插件代码故障 | 停活动再回退兼容代码;不直接还原旧资产库 |
数据库备份恢复会让已发生交易的防重记录倒退,必须停写并对账,不能 把恢复数据库当作无损的代码回滚。迁移先做向后兼容的增量变更,确认 旧版本不能安全使用新结构时禁止直接降级运行。
14. 实施顺序与验收
| 阶段 | 实施范围 | 完成证据 |
|---|---|---|
| 1 | 冻结首期玩法、身份范围、配置协议、到期政策 | 规格与示例配置评审 |
| 2 | Rust 管理、校验、发布及完整目录 | 发布并发、回滚、认证测试 |
| 3 | 农场快照同步与生命周期,尚不发资产 | 重启、乱序、断网、撤销验证 |
| 4 | 本地掉落、领奖、兑换与账本 | 并发、重放、事务失败验证 |
| 5 | 过期结算、归档、运维指标 | 截止竞争、断点续跑、恢复演练 |
| 6 | 测试群及灰度活动 | 实际菜单、掉落、兑换、到账核对 |
必须覆盖的异常场景:
- 开始和结束的精确边界、北京时间零点、跨日限购、重启跨越截止时间。
- 同一消息并发重放、同一任务并发领奖、最后一份限购并发兑换。
- 扣币后入库失败、提交后回复失败、数据库提交结果未知。
- 发布后客户端掉线、旧授权未到期时紧急停用、乱序和空目录响应。
- 有效期到期时
304、下载失败、奖励 ID 不存在、旧插件能力不足。 - 清理过程中仍有交易、清理中断重启、历史收据重放、永久道具保留。
- 若选 B:事件迟到与重复、确认丢失、重复交付、退款与发货竞争。
这些为后续验收要求,本轮未新增测试文件或执行业务回归。
15. 建议默认值与待确认选择
| 决策 | 建议首期默认 | 何时需要调整 |
|---|---|---|
| 资产归属 | A:本地活动账户 | 跨部署共用余额、全服限量时选 B |
| 接入方式 | 60 秒轮询 + 抖动 | 对上线响应有更高要求时加 SSE |
| 离线授权 | 最长 5 分钟 | 需即时停用时逐笔在线授权 |
| 交互 | 固定入口 + 稳定编号 + 日常掉落 | 引用菜单能力验证后增强 |
| 首期玩法 | 收获掉落、累计任务、兑换已有物品 | 新玩法先发布客户端能力 |
| 价格与奖励 | 活动开始后冻结 | 先暂停并排空旧授权后改版 |
| 补兑期 | 掉落结束后再留 3 天 | 各期上架前确定并展示 |
| 剩余活动币 | 到期失效,不自动折算 | 如要折算需独立结算规格 |
| 到期处理 | 自动停止、延后归档,不硬删 | 运营保留策略确定后再实现删除 |
| 通知范围 | 用户主动查询与实际操作提示 | 群发需另行确定渠道与授权 |
以上建议未因生成本文而自动成为已批准的实现需求。 实施前最关键的选择是:是否确实需要“跨机器人共享活动资产”。 它决定采用本地事务即可完成的 A,还是需要跨库交付与对账的 B。
16. 本轮交付范围
- 新增本文及文档索引入口;未修改业务代码、legacy、版本文件或数据库。
- 阅读现有项目约定与相关设计文档,未进行结构性源码调用链调查。
- 外部资料仅用于核对 Rust 库职责和 PostgreSQL 通知语义;架构取舍为本文建议。
- 未实现或部署 Rust 服务、未重启机器人、未执行真实 QQ 群验证。