package registerreward import ( "context" "fmt" "strconv" "strings" "time" "github.com/redis/go-redis/v9" ) // parseRegisterRewardEvent 把 Redis Stream 消息解析成统一事件对象。 func parseRegisterRewardEvent(message redis.XMessage) (registerRewardEvent, error) { eventID := strings.TrimSpace(toRegisterRewardString(message.Values["eventId"])) if eventID == "" { return registerRewardEvent{}, fmt.Errorf("eventId is required") } sysOrigin := strings.ToUpper(strings.TrimSpace(toRegisterRewardString(message.Values["sysOrigin"]))) if sysOrigin == "" { return registerRewardEvent{}, fmt.Errorf("sysOrigin is required") } userID, err := toRegisterRewardInt64(message.Values["userId"]) if err != nil { return registerRewardEvent{}, fmt.Errorf("invalid userId: %w", err) } if userID <= 0 { return registerRewardEvent{}, fmt.Errorf("invalid userId") } countryID, _ := toRegisterRewardInt64(message.Values["countryId"]) return registerRewardEvent{ EventID: eventID, SysOrigin: sysOrigin, UserID: userID, CountryID: countryID, }, nil } // toRegisterRewardString 把 Stream 字段安全转换成字符串。 func toRegisterRewardString(value any) string { switch typed := value.(type) { case nil: return "" case string: return typed case []byte: return string(typed) default: return fmt.Sprint(typed) } } // toRegisterRewardInt64 把 Stream 字段安全转换成 int64。 func toRegisterRewardInt64(value any) (int64, error) { switch typed := value.(type) { case nil: return 0, fmt.Errorf("value is nil") case int64: return typed, nil case int32: return int64(typed), nil case int: return int64(typed), nil case uint64: return int64(typed), nil case float64: return int64(typed), nil case string: return strconv.ParseInt(strings.TrimSpace(typed), 10, 64) case []byte: return strconv.ParseInt(strings.TrimSpace(string(typed)), 10, 64) default: return strconv.ParseInt(strings.TrimSpace(fmt.Sprint(typed)), 10, 64) } } // isRegisterRewardTerminalStatus 判断该日志状态是否已经终态。 func isRegisterRewardTerminalStatus(status string) bool { switch strings.ToUpper(strings.TrimSpace(status)) { case registerRewardStatusSuccess, registerRewardStatusSkipped: return true default: return false } } // isRegisterRewardNoGroupErr 判断是否是消费者组不存在错误。 func isRegisterRewardNoGroupErr(err error) bool { if err == nil { return false } return strings.Contains(strings.ToUpper(err.Error()), "NOGROUP") } // truncateRegisterRewardMessage 截断错误信息,避免超出数据库字段长度。 func truncateRegisterRewardMessage(message string) string { message = strings.TrimSpace(message) if len(message) <= 255 { return message } return message[:255] } // sleepWithContext 支持被上下文中断的休眠。 func sleepWithContext(ctx context.Context, duration time.Duration) { timer := time.NewTimer(duration) defer timer.Stop() select { case <-ctx.Done(): case <-timer.C: } }