You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
1.6 KiB
73 lines
1.6 KiB
3 years ago
|
package redis_helper
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"crypto/rand"
|
||
|
"encoding/base64"
|
||
|
|
||
|
"github.com/go-redis/redis/v8"
|
||
|
)
|
||
|
|
||
|
type RedisPreempt struct {
|
||
|
key string
|
||
|
password string
|
||
|
lockScript, unlockScript *redis.Script
|
||
|
lastLockStatus bool
|
||
|
}
|
||
|
|
||
|
// CreatePreempt used to create a redis preempt instance
|
||
|
func CreatePreempt(key string) *RedisPreempt {
|
||
|
p := &RedisPreempt{
|
||
|
key: key,
|
||
|
}
|
||
|
p.init()
|
||
|
|
||
|
return p
|
||
|
}
|
||
|
|
||
|
// init redis preempt instance and some script
|
||
|
func (p *RedisPreempt) init() {
|
||
|
byt := make([]byte, 18)
|
||
|
_, _ = rand.Read(byt)
|
||
|
p.password = base64.StdEncoding.EncodeToString(byt)
|
||
|
p.lockScript = redis.NewScript(`
|
||
|
if redis.call('get',KEYS[1]) == ARGV[1] then
|
||
|
return redis.call('expire', KEYS[1], ARGV[2])
|
||
|
else
|
||
|
return redis.call('set', KEYS[1], ARGV[1], 'ex', ARGV[2], 'nx')
|
||
|
end
|
||
|
`)
|
||
|
p.unlockScript = redis.NewScript(`
|
||
|
if redis.call('get',KEYS[1]) == ARGV[1] then
|
||
|
return redis.call('del', KEYS[1])
|
||
|
else
|
||
|
return 0
|
||
|
end
|
||
|
`)
|
||
|
}
|
||
|
|
||
|
// TryLock attempt to lock the master for ttlSecond
|
||
|
func (p *RedisPreempt) TryLock(ttlSecond int) (ok bool, err error) {
|
||
|
ok, err = p.lockScript.Run(context.Background(), redisInstance, []string{p.key}, p.password, ttlSecond).Bool()
|
||
|
p.lastLockStatus = ok
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Unlock try to release the master permission
|
||
|
func (p *RedisPreempt) Unlock() (bool, error) {
|
||
|
if p == nil {
|
||
|
return false, nil
|
||
|
}
|
||
|
|
||
|
return p.unlockScript.Run(context.Background(), redisInstance, []string{p.key}, p.password).Bool()
|
||
|
}
|
||
|
|
||
|
// LastLockStatus get the last preempt status
|
||
|
func (p *RedisPreempt) LastLockStatus() bool {
|
||
|
if p == nil {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
return p.lastLockStatus
|
||
|
}
|