| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 |
- package utils
- import (
- "context"
- "errors"
- "time"
- )
- var ErrRedisNotInitialized = errors.New("redis client is not initialized, set redis_enable=true and restart")
- const redisLockReleaseScript = `
- if redis.call("GET", KEYS[1]) == ARGV[1] then
- return redis.call("DEL", KEYS[1])
- else
- return 0
- end
- `
- // AcquireRedisLock tries to create a distributed lock with key and value.
- // It returns true when lock is acquired, false when lock already exists.
- func AcquireRedisLock(key, value string) (bool, error) {
- if RedisClient == nil {
- return false, ErrRedisNotInitialized
- }
- if key == "" || value == "" {
- return false, errors.New("key and value must not be empty")
- }
- lockTTLMS := redisInt("redis_lock_ttl_ms", 30000)
- opTimeoutMS := redisInt("redis_lock_op_timeout_ms", 1000)
- ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeoutMS)*time.Millisecond)
- defer cancel()
- return RedisClient.SetNX(ctx, key, value, time.Duration(lockTTLMS)*time.Millisecond).Result()
- }
- // ReleaseRedisLock releases lock only when key currently matches value.
- // It returns true when released successfully.
- func ReleaseRedisLock(key, value string) (bool, error) {
- if RedisClient == nil {
- return false, ErrRedisNotInitialized
- }
- if key == "" || value == "" {
- return false, errors.New("key and value must not be empty")
- }
- opTimeoutMS := redisInt("redis_lock_op_timeout_ms", 1000)
- ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeoutMS)*time.Millisecond)
- defer cancel()
- n, err := RedisClient.Eval(ctx, redisLockReleaseScript, []string{key}, value).Int64()
- if err != nil {
- return false, err
- }
- return n == 1, nil
- }
|