goRedisDLM/redisLock/redlock.go

82 lines
1.5 KiB
Go

package redisLock
import (
"context"
"errors"
"fmt"
"time"
"github.com/go-redis/redis/v8"
)
type RedLock struct {
locks []*RedisLockNew
RedLockOptions
}
func (r *RedLock) UnLock() (err error) {
for _, lock := range r.locks {
if _error := lock.UnLock(); _error != nil {
if err == nil {
err = _error
}
}
}
return
}
func (r *RedLock) Lock() error {
successLock := 0
for _, lock := range r.locks {
now := time.Now()
err := lock.Lock()
since := time.Since(now)
if err == nil && since < time.Duration(r.perHostTimeout) {
successLock++
}
}
if successLock < len(r.locks)>>1+1 {
return errors.New("redis lock timeout")
}
return nil
}
type RedisHost struct {
NetWork string
Host string
Pass string
}
func NewRedLock(key string, hosts []*RedisHost, opts ...RedLockOption) (*RedLock, error) {
if len(hosts) < 3 {
return nil, fmt.Errorf("invalid redis host length %d", len(hosts))
}
l := &RedLock{}
for _, opt := range opts {
opt(&l.RedLockOptions)
}
l.repairOption()
if len(hosts)*l.perHostTimeout*10 > l.expireHostTime {
return nil, fmt.Errorf("invalid redis host length %d", len(hosts)*l.perHostTimeout*10)
}
l.locks = make([]*RedisLockNew, 0, len(hosts))
for _, host := range hosts {
client := redis.NewClient(&redis.Options{
Network: host.NetWork,
Addr: host.Host,
Password: host.Pass,
})
l.locks = append(l.locks, NewRedisLock(client, context.Background(), key, WithExpireTime(5)))
}
return l, nil
}