package binanceservice import ( "context" "errors" "fmt" "net" "strings" "time" "github.com/go-admin-team/go-admin-core/logger" "gorm.io/gorm" ) // ErrorType 错误类型 type ErrorType string const ( ErrorTypeNetwork ErrorType = "network" ErrorTypeDatabase ErrorType = "database" ErrorTypeBusiness ErrorType = "business" ErrorTypeSystem ErrorType = "system" ErrorTypeValidation ErrorType = "validation" ErrorTypeTimeout ErrorType = "timeout" ErrorTypeRateLimit ErrorType = "rate_limit" ErrorTypeAuth ErrorType = "auth" ) // ErrorSeverity 错误严重程度 type ErrorSeverity string const ( SeverityLow ErrorSeverity = "low" SeverityMedium ErrorSeverity = "medium" SeverityHigh ErrorSeverity = "high" SeverityCritical ErrorSeverity = "critical" ) // ErrorAction 错误处理动作 type ErrorAction string const ( ActionRetry ErrorAction = "retry" ActionFallback ErrorAction = "fallback" ActionAlert ErrorAction = "alert" ActionIgnore ErrorAction = "ignore" ActionCircuit ErrorAction = "circuit" ActionDegrade ErrorAction = "degrade" ) // ErrorInfo 错误信息 type ErrorInfo struct { Type ErrorType `json:"type"` Severity ErrorSeverity `json:"severity"` Message string `json:"message"` OriginalErr error `json:"-"` Context string `json:"context"` Timestamp time.Time `json:"timestamp"` Retryable bool `json:"retryable"` Action ErrorAction `json:"action"` } // RetryConfig 和 CircuitBreakerConfig 已在 config_optimized.go 中定义 // ErrorHandler 错误处理器 type ErrorHandler struct { config *OptimizedConfig metricsCollector *MetricsCollector circuitBreakers map[string]*CircuitBreaker } // CircuitBreaker 熔断器 type CircuitBreaker struct { name string config CircuitBreakerConfig state CircuitState failureCount int successCount int lastFailTime time.Time nextRetry time.Time halfOpenCalls int } // CircuitState 熔断器状态 type CircuitState string const ( StateClosed CircuitState = "closed" StateOpen CircuitState = "open" StateHalfOpen CircuitState = "half_open" ) // NewErrorHandler 创建错误处理器 func NewErrorHandler(config *OptimizedConfig, metricsCollector *MetricsCollector) *ErrorHandler { return &ErrorHandler{ config: config, metricsCollector: metricsCollector, circuitBreakers: make(map[string]*CircuitBreaker), } } // ClassifyError 分类错误 func (eh *ErrorHandler) ClassifyError(err error, context string) *ErrorInfo { if err == nil { return nil } errorInfo := &ErrorInfo{ OriginalErr: err, Message: err.Error(), Context: context, Timestamp: time.Now(), } // 根据错误类型分类 switch { case isNetworkError(err): errorInfo.Type = ErrorTypeNetwork errorInfo.Severity = SeverityMedium errorInfo.Retryable = true errorInfo.Action = ActionRetry case isDatabaseError(err): errorInfo.Type = ErrorTypeDatabase errorInfo.Severity = SeverityHigh errorInfo.Retryable = isRetryableDatabaseError(err) errorInfo.Action = ActionRetry case isTimeoutError(err): errorInfo.Type = ErrorTypeTimeout errorInfo.Severity = SeverityMedium errorInfo.Retryable = true errorInfo.Action = ActionRetry case isRateLimitError(err): errorInfo.Type = ErrorTypeRateLimit errorInfo.Severity = SeverityMedium errorInfo.Retryable = true errorInfo.Action = ActionRetry case isAuthError(err): errorInfo.Type = ErrorTypeAuth errorInfo.Severity = SeverityHigh errorInfo.Retryable = false errorInfo.Action = ActionAlert case isValidationError(err): errorInfo.Type = ErrorTypeValidation errorInfo.Severity = SeverityLow errorInfo.Retryable = false errorInfo.Action = ActionIgnore case isBusinessError(err): errorInfo.Type = ErrorTypeBusiness errorInfo.Severity = SeverityMedium errorInfo.Retryable = false errorInfo.Action = ActionFallback default: errorInfo.Type = ErrorTypeSystem errorInfo.Severity = SeverityHigh errorInfo.Retryable = true errorInfo.Action = ActionRetry } return errorInfo } // HandleError 处理错误 func (eh *ErrorHandler) HandleError(err error, context string) *ErrorInfo { errorInfo := eh.ClassifyError(err, context) if errorInfo == nil { return nil } // 记录错误指标 if eh.metricsCollector != nil { eh.metricsCollector.RecordError(string(errorInfo.Type), errorInfo.Message, context) } // 根据错误动作处理 switch errorInfo.Action { case ActionAlert: eh.sendAlert(errorInfo) case ActionCircuit: eh.triggerCircuitBreaker(context) case ActionDegrade: eh.enableDegradedMode(context) } // 记录日志 eh.logError(errorInfo) return errorInfo } // RetryWithBackoff 带退避的重试 func (eh *ErrorHandler) RetryWithBackoff(ctx context.Context, operation func() error, config RetryConfig, context string) error { var lastErr error delay := config.RetryDelay for attempt := 1; attempt <= config.MaxRetries; attempt++ { // 检查上下文是否已取消 select { case <-ctx.Done(): return ctx.Err() default: } // 检查熔断器状态 if !eh.canExecute(context) { return fmt.Errorf("circuit breaker is open for %s", context) } // 执行操作 // 注意:config中没有TimeoutPerTry字段,这里暂时注释掉 // if config.TimeoutPerTry > 0 { // var cancel context.CancelFunc // operationCtx, cancel = context.WithTimeout(ctx, config.TimeoutPerTry) // defer cancel() // } err := operation() if err == nil { // 成功,记录成功指标 if eh.metricsCollector != nil { eh.metricsCollector.RecordRetry(true) } eh.recordSuccess(context) return nil } lastErr = err errorInfo := eh.ClassifyError(err, context) // 记录失败 eh.recordFailure(context) // 如果不可重试,直接返回 if errorInfo != nil && !errorInfo.Retryable { logger.Warnf("不可重试的错误 [%s]: %v", context, err) return err } // 最后一次尝试,不再等待 if attempt == config.MaxRetries { break } // 计算下次重试延迟 nextDelay := eh.calculateDelay(delay, config) logger.Infof("重试 %d/%d [%s] 在 %v 后,错误: %v", attempt, config.MaxRetries, context, nextDelay, err) // 等待重试 select { case <-ctx.Done(): return ctx.Err() case <-time.After(nextDelay): delay = nextDelay } } // 记录重试失败指标 if eh.metricsCollector != nil { eh.metricsCollector.RecordRetry(false) } return fmt.Errorf("重试 %d 次后仍然失败 [%s]: %w", config.MaxRetries, context, lastErr) } // calculateDelay 计算重试延迟 func (eh *ErrorHandler) calculateDelay(currentDelay time.Duration, config RetryConfig) time.Duration { nextDelay := time.Duration(float64(currentDelay) * config.BackoffFactor) // 限制最大延迟 if nextDelay > config.MaxRetryDelay { nextDelay = config.MaxRetryDelay } // 添加10%抖动(简化版本,不依赖JitterEnabled字段) jitter := time.Duration(float64(nextDelay) * 0.1) if jitter > 0 { nextDelay += time.Duration(time.Now().UnixNano() % int64(jitter)) } return nextDelay } // canExecute 检查是否可以执行操作(熔断器检查) func (eh *ErrorHandler) canExecute(context string) bool { cb := eh.getCircuitBreaker(context) if cb == nil || !cb.config.Enabled { return true } now := time.Now() switch cb.state { case StateClosed: return true case StateOpen: if now.After(cb.nextRetry) { cb.state = StateHalfOpen cb.halfOpenCalls = 0 return true } return false case StateHalfOpen: return cb.halfOpenCalls < cb.config.HalfOpenMaxCalls default: return true } } // recordSuccess 记录成功 func (eh *ErrorHandler) recordSuccess(context string) { cb := eh.getCircuitBreaker(context) if cb == nil || !cb.config.Enabled { return } switch cb.state { case StateHalfOpen: cb.successCount++ if cb.successCount >= cb.config.SuccessThreshold { cb.state = StateClosed cb.failureCount = 0 cb.successCount = 0 } case StateClosed: cb.failureCount = 0 } } // recordFailure 记录失败 func (eh *ErrorHandler) recordFailure(context string) { cb := eh.getCircuitBreaker(context) if cb == nil || !cb.config.Enabled { return } cb.failureCount++ cb.lastFailTime = time.Now() switch cb.state { case StateClosed: if cb.failureCount >= cb.config.FailureThreshold { cb.state = StateOpen cb.nextRetry = time.Now().Add(cb.config.Timeout) logger.Warnf("熔断器开启 [%s]: 失败次数 %d", context, cb.failureCount) } case StateHalfOpen: cb.state = StateOpen cb.nextRetry = time.Now().Add(cb.config.Timeout) cb.successCount = 0 logger.Warnf("熔断器重新开启 [%s]", context) } } // getCircuitBreaker 获取熔断器 func (eh *ErrorHandler) getCircuitBreaker(context string) *CircuitBreaker { cb, exists := eh.circuitBreakers[context] if !exists { cb = &CircuitBreaker{ name: context, config: eh.config.CircuitBreakerConfig, state: StateClosed, } eh.circuitBreakers[context] = cb } return cb } // triggerCircuitBreaker 触发熔断器 func (eh *ErrorHandler) triggerCircuitBreaker(context string) { cb := eh.getCircuitBreaker(context) if cb != nil && cb.config.Enabled { cb.state = StateOpen cb.nextRetry = time.Now().Add(cb.config.Timeout) logger.Warnf("手动触发熔断器 [%s]", context) } } // sendAlert 发送告警 func (eh *ErrorHandler) sendAlert(errorInfo *ErrorInfo) { // 这里可以集成告警系统,如钉钉、邮件等 logger.Errorf("告警: [%s] %s - %s", errorInfo.Type, errorInfo.Context, errorInfo.Message) } // enableDegradedMode 启用降级模式 func (eh *ErrorHandler) enableDegradedMode(context string) { logger.Warnf("启用降级模式 [%s]", context) // 这里可以实现具体的降级逻辑 } // logError 记录错误日志 func (eh *ErrorHandler) logError(errorInfo *ErrorInfo) { switch errorInfo.Severity { case SeverityLow: logger.Infof("[%s] %s: %s", errorInfo.Type, errorInfo.Context, errorInfo.Message) case SeverityMedium: logger.Warnf("[%s] %s: %s", errorInfo.Type, errorInfo.Context, errorInfo.Message) case SeverityHigh, SeverityCritical: logger.Errorf("[%s] %s: %s", errorInfo.Type, errorInfo.Context, errorInfo.Message) } } // GetCircuitBreakerStatus 获取熔断器状态 func (eh *ErrorHandler) GetCircuitBreakerStatus() map[string]interface{} { status := make(map[string]interface{}) for name, cb := range eh.circuitBreakers { status[name] = map[string]interface{}{ "state": cb.state, "failure_count": cb.failureCount, "success_count": cb.successCount, "last_fail_time": cb.lastFailTime, "next_retry": cb.nextRetry, } } return status } // 错误分类辅助函数 // isNetworkError 判断是否为网络错误 func isNetworkError(err error) bool { if err == nil { return false } // 检查网络相关错误 var netErr net.Error if errors.As(err, &netErr) { return true } // 检查常见网络错误消息 errorMsg := strings.ToLower(err.Error()) networkKeywords := []string{ "connection refused", "connection reset", "connection timeout", "network unreachable", "no route to host", "dns", "socket", } for _, keyword := range networkKeywords { if strings.Contains(errorMsg, keyword) { return true } } return false } // isDatabaseError 判断是否为数据库错误 func isDatabaseError(err error) bool { if err == nil { return false } // 检查GORM错误 if errors.Is(err, gorm.ErrRecordNotFound) || errors.Is(err, gorm.ErrInvalidTransaction) || errors.Is(err, gorm.ErrNotImplemented) { return true } // 检查数据库相关错误消息 errorMsg := strings.ToLower(err.Error()) dbKeywords := []string{ "database", "sql", "mysql", "postgres", "connection pool", "deadlock", "constraint", "duplicate key", } for _, keyword := range dbKeywords { if strings.Contains(errorMsg, keyword) { return true } } return false } // isRetryableDatabaseError 判断是否为可重试的数据库错误 func isRetryableDatabaseError(err error) bool { if err == nil { return false } // 不可重试的错误 if errors.Is(err, gorm.ErrRecordNotFound) { return false } errorMsg := strings.ToLower(err.Error()) nonRetryableKeywords := []string{ "constraint", "duplicate key", "foreign key", "syntax error", } for _, keyword := range nonRetryableKeywords { if strings.Contains(errorMsg, keyword) { return false } } return true } // isTimeoutError 判断是否为超时错误 func isTimeoutError(err error) bool { if err == nil { return false } // 检查超时错误 var netErr net.Error if errors.As(err, &netErr) && netErr.Timeout() { return true } if errors.Is(err, context.DeadlineExceeded) { return true } errorMsg := strings.ToLower(err.Error()) return strings.Contains(errorMsg, "timeout") || strings.Contains(errorMsg, "deadline exceeded") } // isRateLimitError 判断是否为限流错误 func isRateLimitError(err error) bool { if err == nil { return false } errorMsg := strings.ToLower(err.Error()) rateLimitKeywords := []string{ "rate limit", "too many requests", "429", "quota exceeded", "throttle", } for _, keyword := range rateLimitKeywords { if strings.Contains(errorMsg, keyword) { return true } } return false } // isAuthError 判断是否为认证错误 func isAuthError(err error) bool { if err == nil { return false } errorMsg := strings.ToLower(err.Error()) authKeywords := []string{ "unauthorized", "authentication", "invalid signature", "api key", "401", "403", "forbidden", } for _, keyword := range authKeywords { if strings.Contains(errorMsg, keyword) { return true } } return false } // isValidationError 判断是否为验证错误 func isValidationError(err error) bool { if err == nil { return false } errorMsg := strings.ToLower(err.Error()) validationKeywords := []string{ "validation", "invalid parameter", "bad request", "400", "missing required", "invalid format", } for _, keyword := range validationKeywords { if strings.Contains(errorMsg, keyword) { return true } } return false } // isBusinessError 判断是否为业务错误 func isBusinessError(err error) bool { if err == nil { return false } errorMsg := strings.ToLower(err.Error()) businessKeywords := []string{ "insufficient balance", "order not found", "position not found", "invalid order status", "market closed", "symbol not found", } for _, keyword := range businessKeywords { if strings.Contains(errorMsg, keyword) { return true } } return false } // 全局错误处理器实例 var GlobalErrorHandler *ErrorHandler // InitErrorHandler 初始化错误处理器 func InitErrorHandler(config *OptimizedConfig, metricsCollector *MetricsCollector) { GlobalErrorHandler = NewErrorHandler(config, metricsCollector) } // GetErrorHandler 获取全局错误处理器 func GetErrorHandler() *ErrorHandler { return GlobalErrorHandler } // HandleErrorWithRetry 处理错误并重试的便捷函数 func HandleErrorWithRetry(ctx context.Context, operation func() error, context string) error { if GlobalErrorHandler == nil { return operation() } config := RetryConfig{ MaxRetries: 3, RetryDelay: 100 * time.Millisecond, MaxRetryDelay: 5 * time.Second, BackoffFactor: 2.0, ApiRetryCount: 3, DbRetryCount: 3, } return GlobalErrorHandler.RetryWithBackoff(ctx, operation, config, context) }