Files
junhong_cmp_fiber/internal/infrastructure/cardtrafficlock/lock.go
break 5c4d17e9fc
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
收口七月卡状态回调与系列授权兼容契约
完成运营商实名回调、业务事件观测序列与受控配置装配,同时恢复 UR43 已交付的 packages[].remove 字段及旧响应兼容,统一更新 OpenSpec、OpenAPI 和交付文档。

Constraint: 七月测试环境里程碑不新增或运行自动化测试

Rejected: 以必填 operation_type 替换 packages[].remove | 会破坏已交付前端契约

Confidence: high

Scope-risk: broad

Directive: 后续修改系列套餐管理接口必须保持 packages[].remove 和 ShopSeriesGrantResponse 兼容

Tested: go run ./cmd/gendocs;go build -buildvcs=false ./...;openspec validate complete-july-iteration-test-release --strict;git diff --check

Not-tested: 按本 Change 约定未运行 go test,真实运营商与 Gateway 联调延期
2026-07-24 19:59:24 +08:00

50 lines
1.4 KiB
Go

// 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()
}