676 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			676 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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)
 | ||
| } |