Files
main_plugin_farm/docs/23-seasonal-events-and-rust-service.md
T

530 lines
30 KiB
Markdown
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.
# 节日活动交互、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 用户可见示例
```text
【万圣南瓜夜】
掉落截止:11 月 1 日 00:00(北京时间)
兑换截止:11 月 4 日 00:00(北京时间)
糖果:36;任务奖励:1 项可领取
收获作物有机会获得糖果。
查看任务:活动任务
领取奖励:活动领奖
查看商店:活动商店
W26-1 南瓜灯装饰 20 糖果 本期剩余 1
兑换:活动兑换 W26-1
```
上述日期和奖励仅为示例。没有实际可用装饰系统前,不上架装饰奖励;
首期可用已有种子、作物或内部货币,避免创建无效道具。
## 4. 农场如何知道活动上架了
### 4.1 推荐:主动拉取,通知只作加速
```mermaid
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](https://www.postgresql.org/docs/current/sql-notify.html)。
## 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](https://docs.rs/axum/latest/axum/)、
[SQLx Transaction](https://docs.rs/sqlx/latest/sqlx/struct.Transaction.html)。
首期允许使用管理 CLI 调用同一管理服务,不必先建设运营网页。
活动配置只允许受支持的声明式规则,不下发 Python/Rust 脚本、SQL、
模板执行表达式或可执行插件。不支持的新玩法需先升级农场能力。
## 7. 数据设计:每个概念必须参与业务
### 7.1 服务端发布数据(方案 A)
| 概念 | 必要内容及用途 |
|---|---|
| 活动实例 | `instance_id` 标识某年某期;名称、别名用于展示与解析 |
| 配置版本 | `revision`、规则、商品、时间、能力要求、哈希;发布后不可变 |
| 发布记录 | 当前版本、运营状态、目标部署、主活动标记、发布序号 |
| 部署应用结果 | 部署标识、已应用序号、能力集合、最近在线时间、失败码 |
| 操作审计 | 管理员、操作、前后版本、原因、时间;支持故障追溯 |
同一节日每年创建新实例,不修改去年实例来重复开服。
发布时检测同一作用域的主活动时间重叠、别名冲突和商品短编号冲突。
目标名单变更也增加发布序号;被移出范围的客户端必须收到撤销或完整
目录移除语义,不能继续使用无限期缓存。
### 7.2 农场本地数据(方案 A)
| 概念 | 必要内容及用途 |
|---|---|
| 活动快照 | 实例、版本、授权截止、配置正文;重启可恢复且可追溯 |
| 活动账户 | 玩家作用域、实例、余额;防止跨期花币 |
| 任务进度 | 玩家、实例、任务、日期桶、进度;永久任务不用日期桶 |
| 奖励领取记录 | 玩家、实例、任务、日期桶;唯一约束阻止重复领奖 |
| 兑换累计 | 玩家、实例、商品、限购周期桶、已兑换数量;事务限购 |
| 活动账本与收据 | 操作标识、请求摘要、版本、增减额、奖励结果、时间 |
| 日常行为去重 | 原业务操作与活动、规则的关联;避免重放重复掉落 |
玩家键复用实际农场身份范围,不只保存一个 QQ 号;实施时核对机器人、
平台与共享范围。余额和库存只存整数,明确上限并校验乘法溢出。
若已有账本和操作收据能表达这些用途,就扩展复用,不平行创建重复表。
不为首期添加无业务用途的排行榜、跨服积分、全服库存、邮件状态等字段。
快照版本用于解释交易,不能靠“当前最新配置”重算历史收据。
## 8. 发布与版本切换事务
### 8.1 上架步骤
1. 运营创建草稿,设定活动期、兑换期、范围、任务和奖励。
2. 校验时间关系、已有物品 ID、计量单位、上限、编号和能力要求。
3. 在测试部署预演规则,确认菜单中每条指令可执行。
4. 管理请求携带幂等键和预期版本;同键不同参数拒绝。
5. 在一个服务端事务内生成不可变配置版本、更新发布指针和目录序号、
写入操作审计;失败整体回滚。
6. 提交后才响应发布成功。若以后加入可靠推送任务,其待发送记录也在
同一事务写入;不要数据库成功后仅在内存里安排推送。
7. 插件获取目录并校验,在本地事务中安装版本;上报已应用序号。
8. 观察目标部署应用率、错误和时间,再扩大范围。
管理并发修改采用版本条件更新;两名管理员基于同一旧版本发布,至多
一个成功,另一个重新读取后操作。不能用最后写入覆盖来消除冲突。
### 8.2 热更新限制
- 文案可以新版本发布;已接受交易始终按其绑定版本结算。
- 活动币归属、任务语义和商品身份不在进行中重新定义。
- 首期建议活动开始后冻结价格、奖励、限购及掉落规则,避免旧快照
在授权期内继续成交造成不公平;调整通过暂停、等待旧授权耗尽、
发新版本、确认部署应用后恢复完成。
- 严重错误通过新发布序号回退到已知配置,不降低序号,不删除已发生交易。
- 本地交易对快照生效指针和授权有效期在写事务中检查;与同步切换
串行化,不能在事务外读到旧配置后无限期继续写资产。
## 9. 方案 A:本地活动交易
### 9.1 收获掉落和任务进度
一次收获事务中:
1. 查原操作收据;已处理则返回原结果,不再次抽奖。
2. 读取活动快照,检查时间、范围、能力和授权;判定时刻在业务锁取得后
采样,不能沿用排队前的旧时间。
3. 完成原有收获计算与状态更新。
4. 对符合条件的本次实际收获计算活动掉落,更新余额及任务进度。
5. 写入行为去重、活动流水及原操作完整收据,一起提交。
活动停用或授权失效属于正常“不参与活动”,不阻塞基础收获;活动
数据库写失败属于事务失败,不能吞掉异常后提交一半结果。
随机结果记录在已提交收据中。若事务回滚,重新计算不产生已到账的重复奖。
不默认让偷来的作物也触发收获掉落,以免改变现有偷菜事务和经济平衡;
如要支持,单独定义触发类型、计量方式并验证。
### 9.2 任务领奖
在一个事务内检查阶段、已完成进度和领取唯一约束,写领取记录、增加
奖励、写流水和收据,再提交。全部领取以事务内实际可领取集合为准,
并发请求最多领取一次。只查看任务不标记领取。
### 9.3 商店兑换
```text
BEGIN
查幂等键与请求摘要,已成功则返回原收据
校验快照、授权、时间、商品与正整数数量
条件扣活动币:余额 >= 总价
条件更新限购累计:已购 + 本次 <= 上限
向现有种子/作物/内部货币仓储增加奖励
写活动流水和兑换收据
COMMIT
提交后回复 QQ 消息
```
余额不足、限购失败或入库失败时整体回滚,不能只扣币。
任何底层仓储方法不能自行提交。网络与绘图不放进事务。
请求幂等键包含部署、机器人、平台、消息标识与动作命名空间;同键不同
参数拒绝。没有可靠消息 ID 时,需要持久化操作令牌,不能用每次新 UUID。
超时未知结果先查收据,不推断失败后再次扣款;已成功收据的查询不受
活动截止限制。永久奖励留在正常仓库,不能随活动账户清理一并删除。
首期不直接兑换真寻外部金币,以免重新引入跨库原子性问题。
## 10. 方案 B:若以后集中管理活动币
只有需要跨部署共用余额或全服库存时再实施;不能和 A 同时保留两个
可写活动余额。迁移必须暂停入口、结清待办、核对余额并切换唯一权威源。
### 10.1 日常事件可靠上报
- 农场在原收获事务中写业务结果和待上报事件(outbox),提交后发送。
- 服务端按部署和事件 ID 去重;验证已登记部署、规则、玩家范围和时间。
- 服务端同一事务写接收记录、更新进度/活动币、写账本。
- 客户端仅在收到可查询的成功结果后确认事件已交付;超时重试同 ID。
- 明确迟到事件政策:建议最多接受截止前已发生且在宽限期内收到的事件;
事件时间只能来自受信部署,越过宽限期进入核查,不悄悄改变历史结算。
- 未到账进度显示“待同步”,不能拿尚未服务端确认的余额兑换。
### 10.2 中心扣币、农场入库不是一个事务
1. 服务端在一个事务内校验余额与限购,扣币、创建唯一奖励单和交付任务。
2. 农场轮询领取属于本部署的待交付奖励单,或用兑换响应取得该单。
3. 农场在一个本地事务内按 `grant_id` 去重、奖励入库、写入库收据。
4. 农场提交后确认,服务端把奖励单标记已交付。
5. 确认丢失则重发同一奖励单,农场返回已有收据,不二次入库。
玩家看到“兑换已受理,奖励待到账”,到账后才报告已入库。
这里保证的是重试与去重后业务效果一次,不承诺网络只传一次。
待交付任务以数据库为准,多工作者用数据库锁或租约认领并恢复超时任务。
**超时不能自动退款。** 本地可能已经入库,只是确认丢失。
退款需先通过本地持久化终态证明奖励未发放,并将该单永久标记为取消、
拒绝后续交付;无法建立此屏障则保持待核对,不同时退款和重发。
活动结束后仍交付截止前已受理奖励,不能清除尚未确认的交付单。
## 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 服务
1. 确定域名、HTTPS、访问凭据、目标部署范围和备份位置。
2. 建立数据库迁移及恢复流程,演练空库启动和失败回滚。
3. 先部署兼容旧插件的服务,新服务不要求旧插件立即支持活动。
4. 再发布带活动能力的插件;默认活动入口无可用配置时正常提示。
5. 校验服务身份、目录拉取、授权到期和撤销机制。
6. 在测试群演练完整活动生命周期,不能只检查管理 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 群验证。