fix(trader): add safety checks for balance sync

## 修复内容

### 1. 防止除以零panic (严重bug修复)
- 在计算变化百分比前检查 oldBalance <= 0
- 如果初始余额无效,直接更新为实际余额
- 避免 division by zero panic

### 2. 增强错误处理
- 添加数据库类型断言失败的日志
- 添加数据库为nil的警告日志
- 提供更完整的错误信息

## 技术细节

问题场景:如果 oldBalance = 0,计算 changePercent 会 panic

修复后:在计算前检查 oldBalance <= 0,直接更新余额

## 审查发现
- P0: 除以零风险(已修复)
- P1: 类型断言失败未记录(已修复)
- P1: 数据库为nil未警告(已修复)

详细审查报告:code_review_auto_balance_sync.md
This commit is contained in:
ZhouYongyou
2025-11-04 21:02:26 +08:00
parent 1e9df68d80
commit 3a5dea7405

View File

@@ -292,6 +292,31 @@ func (at *AutoTrader) autoSyncBalanceIfNeeded() {
}
oldBalance := at.initialBalance
// 防止除以零:如果初始余额无效,直接更新为实际余额
if oldBalance <= 0 {
log.Printf("⚠️ [%s] 初始余额无效 (%.2f),直接更新为实际余额 %.2f USDT", at.name, oldBalance, actualBalance)
at.initialBalance = actualBalance
if at.database != nil {
type DatabaseUpdater interface {
UpdateTraderInitialBalance(userID, id string, newBalance float64) error
}
if db, ok := at.database.(DatabaseUpdater); ok {
if err := db.UpdateTraderInitialBalance(at.userID, at.id, actualBalance); err != nil {
log.Printf("❌ [%s] 更新数据库失败: %v", at.name, err)
} else {
log.Printf("✅ [%s] 已自动同步余额到数据库", at.name)
}
} else {
log.Printf("⚠️ [%s] 数据库类型不支持UpdateTraderInitialBalance接口", at.name)
}
} else {
log.Printf("⚠️ [%s] 数据库引用为空,余额仅在内存中更新", at.name)
}
at.lastBalanceSyncTime = time.Now()
return
}
changePercent := ((actualBalance - oldBalance) / oldBalance) * 100
// 变化超过5%才更新
@@ -317,7 +342,11 @@ func (at *AutoTrader) autoSyncBalanceIfNeeded() {
} else {
log.Printf("✅ [%s] 已自动同步余额到数据库", at.name)
}
} else {
log.Printf("⚠️ [%s] 数据库类型不支持UpdateTraderInitialBalance接口", at.name)
}
} else {
log.Printf("⚠️ [%s] 数据库引用为空,余额仅在内存中更新", at.name)
}
} else {
log.Printf("✓ [%s] 余额变化不大 (%.2f%%),无需更新", at.name, changePercent)