Files
cursor/plans/POP modifyFee-454dc363.plan.md
ray zhou 2dd9f17da9 ok
2026-06-29 14:51:55 +08:00

181 lines
9.1 KiB
Markdown
Raw Permalink 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.

<!-- 454dc363-a500-4be5-a576-c2dd86e5515a -->
---
todos:
- id: "remove-prewallet-check"
content: "Phase 1: 删除 executeBetWalletTransfer 中 getWallet 预检,改由 wallet bet 返回映射余额不足"
status: pending
- id: "defer-ledger-query"
content: "Phase 1: finalizeSuccessfulTransfer 去掉同步 queryBizLogmarkWalletSuccess(0) + 异步 ledger 回填"
status: pending
- id: "wallet-return-ledger"
content: "Phase 2: slot-wallet update 响应增加 ledger_idPOP 直接写入 provider_tx"
status: pending
- id: "merge-db-updates"
content: "Phase 3可选: 合并 callback_log / provider_tx 多次 UPDATE并加分段耗时监控"
status: pending
isProject: false
---
# POP modifyFee 性能分析与队列化建议
## 结论(直接回答)
**是的,同步路径偏重,但不宜把「整单回调」丢进队列。**
- Controller [`slot-pwa/app/pop/controller/CashController.php`](slot-pwa/app/pop/controller/CashController.php) 本身很薄,性能问题在 [`slot-pwa/app/pop/logic/CashLogic.php`](slot-pwa/app/pop/logic/CashLogic.php)。
- POP 协议要求 **同步返回最新 `balance`**,且 **钱包扣款/派奖必须在响应前完成**,否则厂商会重试或判失败。
- 相比 jdb/quick/gasea只做 wallet + Redis 幂等 + 异步流水POP 额外引入了 **callback_log、provider_tx、game_round** 三套分表状态机,单次成功回调大约 **6~10 次 DB 写 + 2~3 次 wallet HTTP**
- **已有异步**:用户交易流水(`TransactionLogService::log``pwa_transaction_log` worker、局终事件`GameRoundEventService::publishFinalSettled`)、试玩活动(`TrialRewardNotifyService` MQ publish
因此:**可以队列化的是「不影响 POP 响应正确性的旁路写/追踪」****不能队列化的是幂等、钱包、局状态校验**。
---
## 当前同步链路(成功路径 BET
```mermaid
sequenceDiagram
participant POP
participant MW as ProviderCallbackLogMiddleware
participant Logic as CashLogic
participant DB as ShardDB
participant Wallet as slot_wallet
participant MQ as RabbitMQ
POP->>MW: TransferInOut
MW->>DB: insert callback_log
MW->>Logic: modifyTransferInOut
Logic->>DB: update callback_log parse/in_progress
Logic->>DB: createOrGet provider_tx
Logic->>DB: loadOrCreate game_round
Logic->>DB: markProcessing / markWalletCalling
Logic->>Wallet: getWallet (BET 余额预检)
Logic->>Wallet: update bet
Logic->>Wallet: queryBizLog
Logic->>DB: markWalletSuccess + round update
Logic->>MQ: TransactionLog (async)
Logic->>DB: markProcessSuccess
Logic->>POP: balance
```
对比 legacy [`slot-pwa/app/quick/service/CashService.php`](slot-pwa/app/quick/service/CashService.php)**无 callback_log / provider_tx / game_round**wallet 成功后只发 MQ 写流水,同步面小很多。
---
## 同步步骤分类
| 步骤 | 位置 | 是否必须同步 | 说明 |
|------|------|-------------|------|
| callback_log 收包落库 | Middleware | 建议保留同步 | 审计与 trace但可合并多次 update |
| provider_tx create-or-get | `resolveProviderTx` | **必须** | 幂等键,防双花;必须在 wallet 前 |
| game_round load/create/validate | `RoundService` | **必须** | 后续 WIN/FINAL 依赖局状态 |
| 风控 evaluate + applyRisk | `handleTransferRiskEvaluation` | **必须**(接入真实风控后) | HOLD/REJECT 需在 wallet 前 |
| getWallet 余额预检 | `executeBetWalletTransfer` | **可优化掉** | wallet 本身会拒余额不足,多 1 次 RTT |
| WalletService bet/win | `invokeWalletBetOrWin` | **必须** | 响应 balance 来源 |
| queryBizLog | `finalizeSuccessfulTransfer` | **可移出热路径** | 仅回填 `wallet_ledger_id`;已有补偿 [`ProviderTxCompensationService`](slot-pwa/app/service/game/ProviderTxCompensationService.php) |
| game_round applyBet/Win/Final | `applyRoundUpdateAfterSuccess` | **必须** | 同局后续回调校验 |
| Redis round 缓存 | `updateRoundStateInfo` | 可弱一致异步 | 有 DB fallback但异步需防乱序 |
| TransactionLog | `TransactionLogService::log` | **已异步** | worker 内还做 VIP/日报/big win |
| callback_log 终态 | `markProcessSuccess` | 可延迟 | 不影响 POP 响应;影响实时排障 |
| UserProfit / RTP stat | `WalletService::bet/win` 内 | 可异步 | Redis 统计,非 POP 协议字段 |
---
## 主要性能瓶颈(按收益排序)
### 1. 冗余 wallet HTTP最高收益、最低风险
**BET 路径双查钱包:**
```686:711:slot-pwa/app/pop/logic/CashLogic.php
$currentWallet = WalletService::getWallet($userInfo->uid, $userInfo->currency);
if ($currentWallet->balance < $feeAmount) {
// ... markRejected ...
}
// ...
return $this->invokeWalletBetOrWin($walletCommand, true);
```
- 先 `getWallet`,再 `updateWallet(bet)`**多 1 次完整 HTTP 往返**。
- 建议:删除预检,直接 `bet()`,按 wallet 返回/错误码映射 `CODE_INSUFFICIENT_FUNDS`(与 legacy 一致)。
**成功后二次查询 ledger**
```829:839:slot-pwa/app/pop/logic/CashLogic.php
$ledgerQuery = $this->walletGatewayService->queryBizLog(
$transferContext->uid(),
$finalizeContext->walletRequestId,
ProviderTxService::resolveWalletBizType($finalizeContext->txType)
);
$walletLedgerId = (int) ($ledgerQuery['ledger_id'] ?? 0);
$this->providerTxService->markWalletSuccess(..., $walletLedgerId);
```
- 钱包 `update` 响应 [`WalletEntity`](slot-pwa/app/entity/WalletEntity.php) **不含 `ledger_id`**,故又调 `queryBizLog`**再多 1 次 HTTP**。
- 两条路(二选一或组合):
- **A推荐**:扩展 [`slot-wallet`](slot-wallet/app/api/logic/WalletLogic.php) `update` 响应带 `ledger_id`POP 直接写入,去掉热路径 `queryBizLog`。
- **B低改动**:热路径 `markWalletSuccess(ledger_id=0)`,通过现有 `ProviderTxWalletCompensate` 或新建轻量 MQ consumer 异步回填 `wallet_ledger_id`(与 reward_grant 文档中 queryBizLog 补偿模式一致)。
### 2. 多次分表状态机 UPDATE中等收益
单次回调对 `callback_log`、`provider_tx` 分别多次 `UPDATE`parse → in_progress → wallet_calling → successmiddleware 还有 insert。可考虑
- 合并 `markParseSuccess` + `markProcessInProgress` 为一次写(需改 Model SQL
- provider_tx 状态迁移合并processing + wallet_calling 若对排障非强依赖可合并)。
- **注意**:这是 DB 优化,不是 MQ队列化这些状态反而增加一致性复杂度。
### 3. 适合队列、且不影响 POP 响应的旁路
| 候选 | 做法 | 风险 |
|------|------|------|
| `wallet_ledger_id` 回填 | MQ / 定时补偿 | 低;审计字段短暂为 0 |
| `callback_log` 终态写 | 响应后 defer 或 MQ | 中;实时查 log 延迟 |
| `UserProfitService` / `GameUserRechargeRtpStatService` | 挪到 TransactionLog worker | 低;统计延迟秒级 |
| Redis round 缓存更新 | 响应后 MQ | 中;需 uid+round 有序消费 |
**不适合队列:**
- 整个 `modifyFee` / wallet bet-win厂商等 balance
- `provider_tx` 幂等创建(必须先于 wallet
- `game_round` 聚合更新(同局后续回调依赖)
---
## 与「全异步回调」方案的边界
若把 wallet 也异步化:
- POP 无法立即拿到 balance → **协议不满足**
- 失败重试会与幂等、局状态、钱包状态产生 **竞态**,需大量补偿与对账
现有设计已采用更合理模式:**同步关键路径 + 异步旁路**流水、局终事件。POP 的问题是 **关键路径上叠了审计表 + 多余 HTTP**,而非「异步做得不够」。
---
## 建议实施顺序(若后续要改代码)
### Phase 1 — 热路径减负(推荐先做,改动集中在 slot-pwa
1. 去掉 BET 前 `getWallet` 预检,统一由 wallet 拒单。
2. `finalizeSuccessfulTransfer` 去掉同步 `queryBizLog``markWalletSuccess(ledger_id=0)` + 触发异步回填(复用 `ProviderTxCompensationService` 或新增 `provider_tx_ledger_backfill` 队列)。
3. 补充 Feature 测试余额不足、幂等重复、wallet 成功但 ledger 延迟回填。
### Phase 2 — 跨服务优化(需 slot-wallet 配合)
1. `POST /api/wallet/update` 响应增加 `ledger_id`bet/win 写入后返回)。
2. slot-pwa 优先读响应字段,补偿任务作兜底。
### Phase 3 — DB/观测优化(可选)
1. 合并 callback_log / provider_tx 多次 UPDATE。
2. 对 `modifyTransferInOut` 加分段耗时 metricsmiddleware / provider_tx / round / wallet / finalize用数据验证 Phase 1/2 收益。
---
## 预期收益(量级)
- Phase 1BET 成功路径 **减少 1~2 次 wallet HTTP**(通常 20~80ms/次,视网络与 wallet 负载)。
- Phase 2WIN/FINAL 成功路径再 **减少 1 次 queryBizLog**
- 队列化旁路ledger 回填、统计):**不缩短 POP 感知 RTT 的主矛盾**,但降低峰值时 wallet/DB 叠加压力。
**不能指望**:把 callback_log / provider_tx / game_round 全部异步后 POP RTT 接近 quick/jdb——这三张表是 POP 架构的有意同步成本,用于幂等、审计、局聚合。