Files
cursor/plans/provider_callback_log_308e4907.plan.md
ray zhou ad623aad91 ok
2026-05-29 18:16:34 +08:00

11 KiB
Raw Blame History

name, overview, todos, isProject
name overview todos isProject
Provider Callback Log 在 slot-pwa 按分库分表(对齐 GameResultLogModel落地 game_provider_callback_log_{NN},并实现 POP 回调全链路(收包落库 → 验签/解析/处理状态)。其余厂商后续 PR 扩展。
id content status
shard-ddl-model CreateSharedTable 增加 callback_log 分表 DDLshard/GameProviderCallbackLogModel + Params + IdGenerator completed
id content status
callback-service ProviderCallbackLogService按 shardUid 路由)+ config/game_gateway.php completed
id content status
pop-middleware ProviderCallbackLogMiddleware + pop 中间件链 + POPAuthMiddleware 验签回写 completed
id content status
pop-logic CashLogic/CashController parse/process 状态(含重复 tid、BALANCE completed
id content status
tests Feature 测试shard 写入/更新)+ docker phpunitverify-slot-backend.sh completed
false

Provider 原始回调日志02实现计划

范围(已确认)

  • 本期:分库分表 DDL + Shard Model/Service + POP 两条路由接入 + PHPUnit
  • 后续 PRgasea / quick / jsgame / bbgt / jdb

明确不做(属 03_provider_tx.mdgame_provider_tx_01、wallet 改造、Round 聚合。

文档与 DDL:已与 02 §4.1slot-pwa/db/game_provider_callback_log_shard.sql 对齐(无 gateway_version;含分库分表说明)。


现状与约束

现状
POP 路由 config/route.php /pop/Cash/Get/pop/Cash/TransferInOut
POP 验签 POPAuthMiddleware 验签在 Controller 前
分表参考(本期主参考) app/model/shard/GameResultLogModel.php + CreateSharedTable
非分表参考 GameLaunchSessionModel 仅用于 Launch Session用于 callback_log
ID 生成 IdGenerator::nextGameResultId() 同款 Redis 序号 + 毫秒时间戳

需求文档表名 game_provider_callback_log_01 表示逻辑表前缀;物理表为 user_transaction_{dbNN}.game_provider_callback_log_{tableNN}(与 game_result_log_{NN} 同库族)。


分库分表设计

路由规则(对齐 GameResultLog

// GameResultLogModel
getPreDatabase() => 'user_transaction'
getPreTable()    => 'game_provider_callback_log'  // 物理表 game_provider_callback_log_01..NN
getShardKey()    => 'uid'
  • 构造:new GameProviderCallbackLogModel($shardUid),由 ShardService crc32($shardUid) % (库数×表数) 定位库表。
  • 写入:insertData()(同 TransactionLog::insertGameResult)。
  • 更新:updateByWhere(),条件必须含 id + uid(分片键),例如 ['id' => $id, 'uid' => $shardUid]

分片键 uid 的选取(收包时)

场景 shardUid
POP 已带 userid (int) post.userid
尚未解析 / 验签失败但 body 无 uid 0(需求允许 uid=0,仍落同一分片桶,保留审计)
解析成功后 uid 与收包时不一致 不迁移分片;仅 UPDATE 修正行内 uid 等业务字段(行已在收包分片,避免跨库搬家)

Request 上下文Middleware 写入Logic/Middleware 读取):

  • providerCallbackLogId — 雪花主键
  • providerCallbackShardUid — 分片键,后续所有 UPDATE 必带

GameResultLog 的差异

GameResultLog callback_log
汇总库 s_all.* app/model/all/GameResultLogModel + MQ 同步 本期不做(无跨分片报表需求;后续若要全局检索再加 DBSync
字段 精简结果字段 需求全文raw_body/headers、验签/解析/处理状态等

处理顺序

sequenceDiagram
    participant Provider
    participant LogMW as ProviderCallbackLogMiddleware
    participant PopAuth as POPAuthMiddleware
    participant Logic as CashLogic
    participant Shard as user_transaction_XX.game_provider_callback_log_YY

    Provider->>LogMW: POST
    LogMW->>LogMW: resolveShardUid from post
    LogMW->>Shard: INSERT id=nextProviderCallbackLogId
    LogMW->>PopAuth: request + logId + shardUid
    PopAuth->>Shard: UPDATE verify_status
    PopAuth->>Logic: handler
    Logic->>Shard: UPDATE parse/process

1. 数据库(分表 DDL

修改 CreateSharedTable

createShareTable() 循环内、createGameResultTable() 之后增加 createGameProviderCallbackLogTable($db, $num)

  • 库:user_transaction_01user_transaction_{share_database_num}
  • 表:game_provider_callback_log_01game_provider_callback_log_{share_table_num}
  • 字段/索引以 02 §4.1 为准,除外:不建 gateway_version、不建 idx_gateway_version;其余 KEYidx_provider_txidx_roundidx_uid_receivedidx_body_hashidx_process_status)保留
  • 主键 id 非自增,应用写入 IdGenerator::nextProviderCallbackLogId()

参考 SQL文档用非单库执行

新增 slot-pwa/db/game_provider_callback_log_shard.sql:单分片模板 + 注释说明需通过 php webman createSharedTable(或项目既有命令)批量建表。

部署:docker exec ... php webman createSharedTable(与现有 user_transaction_log / game_result_log 相同流程)。


2. 配置

config/game_gateway.php

配置项 用途
callback_request_id_prefix creq_
route_callback_map 路径 → 默认 callback_type
provider_shard_uid_field 厂商 → POST 分片字段POPuserid

RedisKeyManagerServicePROVIDER_CALLBACK_LOG_NEXT_ID
IdGeneratornextProviderCallbackLogId()(对齐 nextGameResultId


3. 领域层

Shard Model — app/model/shard/GameProviderCallbackLogModel.php

继承 BaseShardModel

protected function getPreDatabase(): string { return 'user_transaction'; }
protected function getPreTable(): string { return 'game_provider_callback_log'; }
protected function getShardKey(): string { return 'uid'; }
  • 状态常量:VERIFY_* / PARSE_* / PROCESS_*
  • 数据访问(均需构造时传入 $shardUid
    • insertReceived(GameProviderCallbackLogReceiveParams $params): void(内部 insertData
    • updateVerifyStatus(int $id, ...)
    • updateParseResult(int $id, GameProviderCallbackLogParseParams $params)
    • updateProcessStatus(int $id, ...)
    • findById(int $id): ?arrayfindOne(['id' => $id, 'uid' => $this->_shardVal])

Value Objects可放 app/model/game/app/entity/game/

  • GameProviderCallbackLogReceiveParams — 含 shardUid、落库字段
  • GameProviderCallbackLogParseParams — 解析后业务字段

Service — app/service/game/ProviderCallbackLogService.php

  • recordReceivedFromRequest(Request $request): void — 解析 shardUid、生成 id/request_id同步 new GameProviderCallbackLogModel($shardUid)->insertReceived(...),设置 $request->providerCallbackLogId / providerCallbackShardUid
  • markVerify*(int $shardUid, int $id, ...)
  • markParse*(int $shardUid, int $id, ...)
  • markProcess*(int $shardUid, int $id, ...)

所有 mark 方法内部统一:new GameProviderCallbackLogModel($shardUid)->updateByWhere(['id' => $id, 'uid' => $shardUid], ...)


4. MiddlewarePOP 本期)


5. POP Logic

CashLogic / CashController

  • $request 读取 providerCallbackLogId + providerCallbackShardUid
  • balance / modifyTransferInOutparse/process 状态;重复 tid → PROCESS_DUPLICATE
  • Validate 失败:PARSE_FAILED + PROCESS_REJECTED(保留已落库的 raw 证据)

6. 测试

参照分表写入方式(非 LaunchSession 单表):

docker exec -w /app/www/slot/slot-pwa php82 ./vendor/bin/phpunit


7. 验收对照POP + 分表)

验收项 实现
原始请求可追溯 raw_body / raw_headers 写入对应分片表
验签/解析失败仍有行 Middleware 先 INSERTshardUid 可为 0
BALANCE 仅 callback_log 无 provider_tx
重复回调多条 log 每次 INSERTtid 重复 → process_status=3
分库分表 与 GameResultLog 相同 user_transaction_*

8. 后续 PR

  • 其它厂商 Middleware + provider_shard_uid_field
  • 可选:app/model/all/GameProviderCallbackLogModel + DBSync仅当需要 s_all 汇总检索时)

关键文件

操作 路径
修改 app/command/CreateSharedTable.php
新增 db/game_provider_callback_log_shard.sql(模板)
新增 app/model/shard/GameProviderCallbackLogModel.php
新增 app/model/game/GameProviderCallbackLog*Params.php
新增 app/service/game/ProviderCallbackLogService.php
新增 app/middleware/ProviderCallbackLogMiddleware.php
修改 IdGenerator.php, RedisKeyManagerService.php, middleware.php, POPAuthMiddleware.php
修改 app/pop/logic/CashLogic.php, app/pop/controller/CashController.php
新增 tests/Feature/GameProviderCallbackLogShardModelTest.php

完成编码后执行 ~/.cursor/hooks/verify-slot-backend.sh 并粘贴输出。