收口七月卡状态回调与系列授权兼容契约
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
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 联调延期
This commit is contained in:
49
internal/infrastructure/cardtrafficlock/lock.go
Normal file
49
internal/infrastructure/cardtrafficlock/lock.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// 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()
|
||||
}
|
||||
Reference in New Issue
Block a user