Files
junhong_cmp_fiber/scripts/benchmark/mock_gateway.go
huang 18daeae65a
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m17s
feat: 钱包系统分离 - 代理钱包与卡钱包完全隔离
## 变更概述
将统一钱包系统拆分为代理钱包和卡钱包两个独立系统,实现数据表和代码层面的完全隔离。

## 数据库变更
- 新增 6 张表:tb_agent_wallet、tb_agent_wallet_transaction、tb_agent_recharge_record、tb_card_wallet、tb_card_wallet_transaction、tb_card_recharge_record
- 删除 3 张旧表:tb_wallet、tb_wallet_transaction、tb_recharge_record
- 代理钱包:按 (shop_id, wallet_type) 唯一标识,支持主钱包和分佣钱包
- 卡钱包:按 (resource_type, resource_id) 唯一标识,支持物联网卡和设备

## 代码变更
- Model 层:新增 AgentWallet、AgentWalletTransaction、AgentRechargeRecord、CardWallet、CardWalletTransaction、CardRechargeRecord 模型
- Store 层:新增 6 个独立 Store,支持事务、乐观锁、Redis 缓存
- Service 层:重构 commission_calculation、commission_withdrawal、order、recharge 等 8 个服务
- Bootstrap 层:更新 Store 和 Service 依赖注入
- 常量层:按钱包类型重新组织常量和 Redis Key 生成函数

## 技术特性
- 乐观锁:使用 version 字段防止并发冲突
- 多租户:支持 shop_id_tag 和 enterprise_id_tag 过滤
- 事务管理:所有余额变动使用事务保证 ACID
- 缓存策略:Cache-Aside 模式,余额变动后删除缓存

## 业务影响
- 代理钱包和卡钱包业务完全隔离,互不影响
- 为独立监控、优化、扩展打下基础
- 提升代理钱包的稳定性和独立性

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-25 09:51:00 +08:00

265 lines
7.0 KiB
Go
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.
//go:build ignore
// +build ignore
package main
import (
"encoding/json"
"fmt"
"log"
"math/rand"
"net/http"
"os"
"sync/atomic"
"time"
)
// 统计计数器
var (
totalRequests int64
successRequests int64
failedRequests int64
startTime time.Time
fastMode bool // 快速模式:低延迟
)
// GatewayResponse 模拟网关响应
type GatewayResponse struct {
Code int `json:"code"`
Msg string `json:"msg"`
TraceID string `json:"traceId"`
Data json.RawMessage `json:"data"`
}
func main() {
startTime = time.Now()
rand.Seed(time.Now().UnixNano())
// 检查是否启用快速模式
if os.Getenv("FAST_MODE") == "1" || os.Getenv("FAST_MODE") == "true" {
fastMode = true
fmt.Println("⚡ 快速模式已启用(延迟: 10-50ms")
} else {
fmt.Println("🐢 真实模式(延迟: 200ms-4s")
fmt.Println(" 提示: 设置 FAST_MODE=1 可启用快速模式")
}
// 实名查询接口(匹配 gateway client 的路径)
http.HandleFunc("/flow-card/realname-status", handleRealnameQuery)
// 流量查询接口
http.HandleFunc("/flow-card/flow", handleFlowQuery)
// 停机接口
http.HandleFunc("/flow-card/cardStop", handleStopCard)
// 复机接口
http.HandleFunc("/flow-card/cardStart", handleStartCard)
// 卡状态查询接口
http.HandleFunc("/flow-card/status", handleCardStatus)
// 统计接口
http.HandleFunc("/stats", handleStats)
fmt.Println("=== Mock Gateway 服务器启动 ===")
fmt.Println("监听端口: 8888")
fmt.Println("模拟响应时间: 200ms - 4s")
fmt.Println("")
fmt.Println("接口列表:")
fmt.Println(" POST /flow-card/realname-status - 实名查询")
fmt.Println(" POST /flow-card/flow - 流量查询")
fmt.Println(" POST /flow-card/status - 卡状态查询")
fmt.Println(" POST /flow-card/cardStop - 停机操作")
fmt.Println(" POST /flow-card/cardStart - 复机操作")
fmt.Println(" GET /stats - 查看统计")
fmt.Println("")
fmt.Println("按 Ctrl+C 停止服务器")
log.Fatal(http.ListenAndServe(":8888", nil))
}
// simulateLatency 模拟网络延迟
func simulateLatency() {
var delay time.Duration
if fastMode {
// 快速模式10-50ms
delay = time.Duration(10+rand.Intn(40)) * time.Millisecond
} else {
// 真实模式200ms - 4s
// 80% 概率 200-500ms正常
// 15% 概率 500ms-2s较慢
// 5% 概率 2s-4s很慢
r := rand.Float64()
if r < 0.80 {
delay = time.Duration(200+rand.Intn(300)) * time.Millisecond
} else if r < 0.95 {
delay = time.Duration(500+rand.Intn(1500)) * time.Millisecond
} else {
delay = time.Duration(2000+rand.Intn(2000)) * time.Millisecond
}
}
time.Sleep(delay)
}
// handleRealnameQuery 处理实名查询
func handleRealnameQuery(w http.ResponseWriter, r *http.Request) {
atomic.AddInt64(&totalRequests, 1)
simulateLatency()
// 90% 成功10% 失败
if rand.Float64() < 0.90 {
atomic.AddInt64(&successRequests, 1)
// 随机返回实名状态
statuses := []string{"未实名", "实名中", "已实名"}
status := statuses[rand.Intn(3)]
resp := GatewayResponse{
Code: 200,
Msg: "success",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
Data: json.RawMessage(fmt.Sprintf(`{"status": "%s"}`, status)),
}
json.NewEncoder(w).Encode(resp)
} else {
atomic.AddInt64(&failedRequests, 1)
resp := GatewayResponse{
Code: 500,
Msg: "upstream error",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
}
json.NewEncoder(w).Encode(resp)
}
}
// handleFlowQuery 处理流量查询
func handleFlowQuery(w http.ResponseWriter, r *http.Request) {
atomic.AddInt64(&totalRequests, 1)
simulateLatency()
if rand.Float64() < 0.90 {
atomic.AddInt64(&successRequests, 1)
// 随机返回流量数据(匹配 FlowUsageResp 结构)
usedFlow := rand.Intn(10000)
resp := GatewayResponse{
Code: 200,
Msg: "success",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
Data: json.RawMessage(fmt.Sprintf(`{"usedFlow": %d, "unit": "MB"}`, usedFlow)),
}
json.NewEncoder(w).Encode(resp)
} else {
atomic.AddInt64(&failedRequests, 1)
resp := GatewayResponse{
Code: 500,
Msg: "upstream error",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
}
json.NewEncoder(w).Encode(resp)
}
}
// handleStopCard 处理停机操作
func handleStopCard(w http.ResponseWriter, r *http.Request) {
atomic.AddInt64(&totalRequests, 1)
simulateLatency()
if rand.Float64() < 0.95 {
atomic.AddInt64(&successRequests, 1)
resp := GatewayResponse{
Code: 200,
Msg: "success",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
Data: json.RawMessage(`{"result": "stopped"}`),
}
json.NewEncoder(w).Encode(resp)
} else {
atomic.AddInt64(&failedRequests, 1)
resp := GatewayResponse{
Code: 500,
Msg: "stop failed",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
}
json.NewEncoder(w).Encode(resp)
}
}
// handleStartCard 处理复机操作
func handleStartCard(w http.ResponseWriter, r *http.Request) {
atomic.AddInt64(&totalRequests, 1)
simulateLatency()
if rand.Float64() < 0.95 {
atomic.AddInt64(&successRequests, 1)
resp := GatewayResponse{
Code: 200,
Msg: "success",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
Data: json.RawMessage(`{"result": "started"}`),
}
json.NewEncoder(w).Encode(resp)
} else {
atomic.AddInt64(&failedRequests, 1)
resp := GatewayResponse{
Code: 500,
Msg: "start failed",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
}
json.NewEncoder(w).Encode(resp)
}
}
// handleCardStatus 处理卡状态查询
func handleCardStatus(w http.ResponseWriter, r *http.Request) {
atomic.AddInt64(&totalRequests, 1)
simulateLatency()
if rand.Float64() < 0.90 {
atomic.AddInt64(&successRequests, 1)
// 随机返回卡状态1-正常0-停机
cardStatus := rand.Intn(2)
resp := GatewayResponse{
Code: 200,
Msg: "success",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
Data: json.RawMessage(fmt.Sprintf(`{"status": %d}`, cardStatus)),
}
json.NewEncoder(w).Encode(resp)
} else {
atomic.AddInt64(&failedRequests, 1)
resp := GatewayResponse{
Code: 500,
Msg: "query failed",
TraceID: fmt.Sprintf("trace-%d", time.Now().UnixNano()),
}
json.NewEncoder(w).Encode(resp)
}
}
// handleStats 返回统计信息
func handleStats(w http.ResponseWriter, r *http.Request) {
elapsed := time.Since(startTime).Seconds()
total := atomic.LoadInt64(&totalRequests)
success := atomic.LoadInt64(&successRequests)
failed := atomic.LoadInt64(&failedRequests)
qps := float64(total) / elapsed
successRate := float64(0)
if total > 0 {
successRate = float64(success) * 100 / float64(total)
}
stats := map[string]interface{}{
"uptime_seconds": elapsed,
"total_requests": total,
"success_count": success,
"failed_count": failed,
"qps": qps,
"success_rate": fmt.Sprintf("%.2f%%", successRate),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(stats)
}