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 }