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 联调延期
50 lines
1.4 KiB
Go
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()
|
|
}
|