7.7 KiB
name, overview, todos, isProject
| name | overview | todos | isProject | |||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 充值用户 Redis 集合 | 在 center 注册共享 Redis key `userRecharged`,wallet 侧一次性脚本从分片 `wallet_stat` 回填历史充值用户,并在 `recharge` / `rechargeSign` 成功后实时 SADD 到共享 Redis 集合。 |
|
false |
Wallet 充值用户共享 Redis 集合
目标
维护一个全局、持久的共享 Redis Set,成员为「曾成功充值」的用户 uid(口径:wallet_stat.total_deposit > 0,与 每日返水需求 中「充值用户」一致)。供后续活动(如每日返水结算)用 SISMEMBER 快速判断,避免逐用户查库。
你已确认:
- Key:
userRecharged→ Redisuser:recharged recharge与rechargeSign均写入集合
架构与数据流
flowchart LR
subgraph center [slot_center]
Sharerediskey["config/sharerediskey.php"]
ShareConfigAPI["/innerapi/share-config/all"]
end
subgraph wallet [slot_wallet]
BackfillCmd["BackfillRechargedUidSet command"]
WalletLogic["WalletLogic::recharge / rechargeSign"]
RechargedSvc["RechargedUidSetService"]
StatDB["wallet_XX.wallet_stat_YY"]
end
ShareRedis["Redis connection share"]
Sharerediskey --> ShareConfigAPI
ShareConfigAPI --> RechargedSvc
BackfillCmd --> StatDB
BackfillCmd --> RechargedSvc
WalletLogic --> RechargedSvc
RechargedSvc --> ShareRedis
1. Center:注册共享 Key
文件:slot_center/config/sharerediskey.php
在数组末尾增加(含注释):
'userRecharged' => 'user:recharged', // set:曾充值用户 uid(wallet 维护)
该文件已通过 ShareConfigController::all() 下发为 sharerediskey.*,各服务经 ShareConfigService::get('sharerediskey.userRecharged') 读取。
部署顺序:先发布 center,再发布 wallet(否则 wallet 会落到 fallback 默认值,key 不一致)。
2. Wallet:Key 解析与写入封装
2.1 RedisKeyManagerService
文件:slot_wallet/app/service/RedisKeyManagerService.php
新增方法(与现有 sourceRealDataKey 一致,从 center 取 key):
public static function getUserRechargedSetKey(): string
{
return ShareConfigService::get('sharerediskey.userRecharged', 'user:recharged');
}
2.2 新建 RechargedUidSetService
路径:slot_wallet/app/service/wallet/RechargedUidSetService.php
职责(公共能力,避免 Logic 直接拼 Redis):
add(int $uid): void—Redis::connection('share')->sAdd($key, (string)$uid)- key 来自
RedisKeyManagerService::getUserRechargedSetKey() - 失败只
LoggerService::error,不抛异常(与WalletLogic::recharge()内sendConsoleBus/createTask等非阻断副作用一致) - 不设 expire(成员为永久「曾充值」标记;
SADD幂等)
参考:slot_risk 对 connection('share')->sAdd 的用法;config/redis.php 已配置 share 连接。
3. 充值链路:实时写入
文件:slot_wallet/app/api/logic/WalletLogic.php
在以下两处、total_deposit 递增且 RechargeExchangeService::recharge() 之后,调用 RechargedUidSetService::add($uid):
| 方法 | 约行号 | 说明 |
|---|---|---|
recharge() |
~782 后 | 正常支付充值 |
rechargeSign() |
~820 后 | 签到购,累加统计 |
放在现有 try/catch 块内即可,无需单独 try。
不扩展范围:全库仅这两处递增 total_deposit(已 grep 确认),无需 hook inc() 或其它 type。
4. 一次性回填脚本
4.1 Webman Command
路径:slot_wallet/app/command/BackfillRechargedUidSet.php
$defaultName = 'backfillRechargedUidSet'- 结构参考
CleanupWalletLog.php:LoggerService::initGenerateTraceId、stdout 汇总、异常返回FAILURE
选项:
| Option | 作用 |
|---|---|
--dry-run |
只统计 uid 数量,不写 Redis |
--rebuild |
执行前 DEL 目标 set(全量重建;默认增量 SADD,可重复跑) |
--batch-size |
每批 SADD 成员数,默认 500 |
4.2 扫描逻辑
按 InitDB::initWalletStat 的分片循环:
for ($i = 1; $i <= $shardInfo['database_num']; $i++) {
$db = sprintf('wallet_%02d', $i);
for ($j = 1; $j <= $shardInfo['table_num']; $j++) {
$table = "{$db}.wallet_stat_" . sprintf('%02d', $j);
// SELECT DISTINCT uid FROM {$table} WHERE total_deposit > 0
}
}
- 使用
DISTINCT uid(表主键(uid, currency),多币种各一行,同一 uid 只入 set 一次) - 分批
sAdd($key, ...$uids)写入connection('share') - 输出:每表行数、总 uid 数、最终
SCARD
4.3 执行命令(Docker)
docker exec -w /app/www/slot/slot_wallet php82 php webman backfillRechargedUidSet --rebuild
# 预检
docker exec -w /app/www/slot/slot_wallet php82 php webman backfillRechargedUidSet --dry-run
建议上线步骤:
- 发布 center(
userRecharged配置) - 发布 wallet(Service + Logic + Command)
- 低峰执行
backfillRechargedUidSet --rebuild(或先--dry-run核对数量) - 之后新充值由 Logic 自动
SADD
5. 测试(wallet 仓库)
| 项 | 方式 |
|---|---|
RechargedUidSetService |
单元测试 mock Redis::connection('share'),或集成测试用真实 share Redis(若 CI 有) |
WalletLogic |
在现有 WalletControllerUpdateTest / recharge 相关用例后断言 set 含 uid(可选,依赖 share Redis) |
| Command | 本地 --dry-run + 小环境 --rebuild 后 SCARD 抽样 SISMEMBER |
至少保证:Service 在 key 存在时调用 sAdd 且不抛异常;Command SQL 与分片配置可读。
6. 不在本次范围(供后续)
- 消费方(如
slot_console每日返水 cron)改为SISMEMBER:需在对应服务增加ShareConfigService::get('sharerediskey.userRecharged')+connection('share'),本次仅 wallet 写入。 - center 本地
ShareRedisKeyManagerService可不增方法(wallet 直接用RedisKeyManagerService+ShareConfigService,与现有sourceReal一致)。
涉及文件一览
| 仓库 | 文件 | 变更 |
|---|---|---|
| slot_center | config/sharerediskey.php |
+1 key |
| slot_wallet | app/service/RedisKeyManagerService.php |
+getUserRechargedSetKey() |
| slot_wallet | app/service/wallet/RechargedUidSetService.php |
新建 |
| slot_wallet | app/api/logic/WalletLogic.php |
recharge / rechargeSign 各 +1 行调用 |
| slot_wallet | app/command/BackfillRechargedUidSet.php |
新建一次性脚本 |