113 lines
3.0 KiB
Go
113 lines
3.0 KiB
Go
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:
|
|
}
|
|
}
|