61 lines
1.6 KiB
Go
61 lines
1.6 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
"hyapp/pkg/appcode"
|
|
"hyapp/pkg/idgen"
|
|
"hyapp/pkg/xerr"
|
|
)
|
|
|
|
const releaseLuckyGiftSendLockScript = `
|
|
if redis.call("GET", KEYS[1]) == ARGV[1] then
|
|
return redis.call("DEL", KEYS[1])
|
|
end
|
|
return 0
|
|
`
|
|
|
|
type LuckyGiftSendLocker interface {
|
|
AcquireLuckyGiftSendLock(ctx context.Context, appCode string, userID int64, ttl time.Duration) (func(context.Context), error)
|
|
}
|
|
|
|
type RedisLuckyGiftSendLocker struct {
|
|
client *redis.Client
|
|
}
|
|
|
|
func NewRedisLuckyGiftSendLocker(client *redis.Client) *RedisLuckyGiftSendLocker {
|
|
return &RedisLuckyGiftSendLocker{client: client}
|
|
}
|
|
|
|
func (l *RedisLuckyGiftSendLocker) AcquireLuckyGiftSendLock(ctx context.Context, appCode string, userID int64, ttl time.Duration) (func(context.Context), error) {
|
|
if l == nil || l.client == nil {
|
|
return nil, nil
|
|
}
|
|
if userID <= 0 {
|
|
return nil, xerr.New(xerr.InvalidArgument, "lucky gift sender is invalid")
|
|
}
|
|
if ttl <= 0 {
|
|
ttl = 5 * time.Second
|
|
}
|
|
key := luckyGiftSendLockKey(appCode, userID)
|
|
token := idgen.New("lucky_gift_send_lock")
|
|
ok, err := l.client.SetNX(ctx, key, token, ttl).Result()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !ok {
|
|
return nil, xerr.New(xerr.Conflict, "lucky gift send is already processing")
|
|
}
|
|
return func(releaseCtx context.Context) {
|
|
_ = l.client.Eval(releaseCtx, releaseLuckyGiftSendLockScript, []string{key}, token).Err()
|
|
}, nil
|
|
}
|
|
|
|
func luckyGiftSendLockKey(rawAppCode string, userID int64) string {
|
|
return fmt.Sprintf("lucky_gift_send:%s:%s", appcode.Normalize(rawAppCode), strconv.FormatInt(userID, 10))
|
|
}
|