// Package cardtrafficlock 提供卡流量上游请求的统一 Redis 互斥。 package cardtrafficlock import ( "context" "github.com/google/uuid" "github.com/redis/go-redis/v9" "github.com/break/junhong_cmp_fiber/pkg/constants" ) var releaseScript = redis.NewScript(` if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) end return 0 `) // Lock 统一卡流量上游请求互斥,防止过期持有者误删新锁。 type Lock struct { redis *redis.Client } // New 创建卡流量请求锁。 func New(redisClient *redis.Client) *Lock { return &Lock{redis: redisClient} } // Acquire 使用随机令牌获取至少覆盖完整 Gateway 重试窗口的卡级锁。 func (l *Lock) Acquire(ctx context.Context, cardID uint) (string, bool, error) { if l == nil || l.redis == nil { return "", true, nil } token := uuid.NewString() acquired, err := l.redis.SetNX(ctx, constants.RedisCardTrafficSyncLockKey(cardID), token, constants.CardObservationGatewayLockTTL).Result() if err != nil || !acquired { return "", acquired, err } return token, true, nil } // Release 仅由仍持有相同随机令牌的调用方释放卡级锁。 func (l *Lock) Release(ctx context.Context, cardID uint, token string) error { if l == nil || l.redis == nil || token == "" { return nil } return releaseScript.Run(ctx, l.redis, []string{constants.RedisCardTrafficSyncLockKey(cardID)}, token).Err() }