Files
cursor/plans/充值用户_redis_集合_a31b1665.plan.md
ray zhou f71a5c59af ok
2026-05-29 11:21:40 +08:00

7.7 KiB
Raw Blame History

name, overview, todos, isProject
name overview todos isProject
充值用户 Redis 集合 在 center 注册共享 Redis key `userRecharged`wallet 侧一次性脚本从分片 `wallet_stat` 回填历史充值用户,并在 `recharge` / `rechargeSign` 成功后实时 SADD 到共享 Redis 集合。
id content status
center-key slot_center sharerediskey.php 增加 userRecharged => user:recharged completed
id content status
wallet-service walletRedisKeyManagerService + RechargedUidSetServiceshare Redis SADD completed
id content status
wallet-hook WalletLogic::recharge / rechargeSign 成功后调用 RechargedUidSetService::add completed
id content status
backfill-cmd 新建 backfillRechargedUidSet 命令:扫 wallet_stat 分片、--dry-run/--rebuild/--batch-size completed
id content status
tests 补充 Service/集成测试或 dry-run 验证说明 completed
false

Wallet 充值用户共享 Redis 集合

目标

维护一个全局、持久的共享 Redis Set成员为「曾成功充值」的用户 uid口径wallet_stat.total_deposit > 0,与 每日返水需求 中「充值用户」一致)。供后续活动(如每日返水结算)用 SISMEMBER 快速判断,避免逐用户查库。

你已确认:

  • KeyuserRecharged → Redis user:recharged
  • rechargerechargeSign 均写入集合

架构与数据流

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曾充值用户 uidwallet 维护)

该文件已通过 ShareConfigController::all() 下发为 sharerediskey.*,各服务经 ShareConfigService::get('sharerediskey.userRecharged') 读取。

部署顺序:先发布 center再发布 wallet否则 wallet 会落到 fallback 默认值key 不一致)。


2. WalletKey 解析与写入封装

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): voidRedis::connection('share')->sAdd($key, (string)$uid)
  • key 来自 RedisKeyManagerService::getUserRechargedSetKey()
  • 失败只 LoggerService::error,不抛异常(与 WalletLogic::recharge()sendConsoleBus / createTask 等非阻断副作用一致)
  • 不设 expire(成员为永久「曾充值」标记;SADD 幂等)

参考:slot_riskconnection('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.phpLoggerService::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

建议上线步骤

  1. 发布 centeruserRecharged 配置)
  2. 发布 walletService + Logic + Command
  3. 低峰执行 backfillRechargedUidSet --rebuild(或先 --dry-run 核对数量)
  4. 之后新充值由 Logic 自动 SADD

5. 测试wallet 仓库)

方式
RechargedUidSetService 单元测试 mock Redis::connection('share'),或集成测试用真实 share Redis若 CI 有)
WalletLogic 在现有 WalletControllerUpdateTest / recharge 相关用例后断言 set 含 uid可选依赖 share Redis
Command 本地 --dry-run + 小环境 --rebuildSCARD 抽样 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 新建一次性脚本