Giter Site home page Giter Site logo

redsync's People

Contributors

appleboy avatar apty avatar bancek avatar bombsimon avatar btomasini avatar darful avatar dcormier avatar fracasula avatar hjr265 avatar kamronbatman avatar keiichihirobe avatar ldcicconi avatar ldechoux avatar lzakharov avatar maruhyl avatar mehdijoafshani avatar milonoir avatar msroy-asapp avatar nathanbaulch avatar nvartolomei avatar palcalde avatar px3303 avatar rayzyar avatar reinkrul avatar rfyiamcool avatar solidshake avatar subtlepseudonym avatar syuparn avatar vadimkulagin avatar x-martinez avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

redsync's Issues

Can use the transaction of redis

i want to execute multiple redis commmand with transaction using MULTI and EXEC, so i can DISCARD it if something bad happens.but I find it doesn't work when I use the conn (gomodule/redigo/redis/pool.go Get func ).Maybe I made a mistake.
Can anyone help me to do?

thanks in advance.

Need for tutorial at README

From redis official doc https://redis.io/topics/distlock, this is the golang implementation of redlock algorithm.
Having viewed the code for whole afternoon, I think this is excellent work, concise and reliable inplementation.
And i've something else to say, maybe the author can provide some startup tutorial for beginners.
What I want includes, env setups, code snippit for base usage ( Lock and Unlock example for copy-paste,LOL)
It would be great to put this in README as project home page.

What if lock expires before unlock?

l'm a little confused about this lock though l've learn something about redlock.
Suppose l have a 8 seconds lock and the worker goroutine need 10 seconds to be done,(not always, sometimes).Another process in the cluster may get the lock cause it has been expired.
l dont think the extend func will work ,cause lock keeper can't always know how long it has already run.(Suppose a io-wait issue or a long GC pause or something like that.)
Please teach me the right way (or right place) to use.
ps: l'm planing to design a distributed lock to protect a large redis zset ,ensure only one process operates it at mean time.

Failing to release lock without any error

Hi,
I had this problem on 4.4.1 and still have it on 4.5.0 :

mutex.Unlock occasionally returns success=false and err=nil
The lack of error makes it hard to investigate my bug (I'm assuming there is something wrong in how I use it)

This is my code (it runs in a goroutine):

const maxWorkTimeOnBuffer = 5 * time.Second
lockKey := fmt.Sprintf("buffer:ticklock:%d", (*bfr).GetDeviceId())
mutex := rs.NewMutex(lockKey, redsync.WithExpiry(maxWorkTimeOnBuffer), redsync.WithTries(1))
if lockFail := mutex.Lock(); lockFail != nil {
	log.Trace("someone else already has ", lockKey)
	return
}

// release the lock after we're done
defer func(mutex *redsync.Mutex) {
	success, err := mutex.Unlock()
	if !success {
		log.WithError(err).Errorf("failed to release tick lock on buffer %d", (*bfr).GetDeviceId())
	}
}(mutex)

and after that is unrelated code

Context Support

I wish this package supported contexts. This would let me do things like proper canceling, and instrumentation (tracing, for example).

The redigo Pool already has a GetContext method.

The "genValueFunc" only set m.value during "lock" but not in the "unlock"

When trying to overwrite "genValueFunc" for each two thread share one same gen value. One of the behavior like:
m1 = newMutex(withGenValue)
m2 = newMutex(withGenValue)
m1.lock() -> true
m2.unlock() -> true
m2.lock() -> true
m1.unlock() -> true

But in the repo genValueFunc only call during the "lock" period, not on the "unlock" period. The unlock period m.value == "", which not initial.

Could we call GenValueFunc during the mutex initial phase, instead of the "lock" phase?
Else the genValueFunc behavior is not a common sense.

Question about random string length

I noticed that the random string length in genValue is 32bytes. This is double the standard length for most purposes (such as UUIDs). Is there a particular reason? Otherwise I recommend we change it to 16 to increase processing.

b := make([]byte, 32)

Also as a consolation, the implementor can change this using a custom value generation function.

How about adding the ability to override lua scripts?

I need to add lock keys to zset so that in the event of a server crash or update, I do not lose the facts of the previously locks keys.

Right now I have to use such a dirty trick by using overriding the value of a private global variable:

//go:linkname deleteScript github.com/go-redsync/redsync/v4.deleteScript
var deleteScript = redis.NewScript(1, `
	if redis.call("GET", KEYS[1]) == ARGV[1] then
		if KEYS[1] == "webhook_blocked" then
			redis.call("ZREM", "webhook_blocked_expires", KEYS[1])
		end
		return redis.call("DEL", KEYS[1])
	else
		return 0
	end
`)

//go:linkname touchScript github.com/go-redsync/redsync/v4.touchScript
var touchScript = redis.NewScript(1, `
	if redis.call("GET", KEYS[1]) == ARGV[1] then
		if KEYS[1] == "webhook_blocked" then
			redis.call("ZADD", "webhook_blocked_expires", ARGV[2], KEYS[1])
		end
		return redis.call("PEXPIRE", KEYS[1], ARGV[2])
	else
		return 0
	end
`)

One could use a transaction, but the eval command does not support transactionality.
What do you think about this? Can I create a pull request?

Comments about runtime errors appear invalid

Both Unlock and Extend state its a runtime error if the lock isn't held, however given locks can timeout its impossible to know if we hold the lock.

Also looking at the code I can't see any way we can get runtime error from this case.

Finally I've tried calling mtx.Unlock() multiple times as well as mtx.Extend() after mtx.Unlock() and no runtime error occurred.

Given the evidence I believe the docs are inaccurate and the reference to runtime errors should be removed.

No indication if the conn encounters an error

Pool.Get() always returns a connection, even in cases where the pool fails to dial redis. In this case, whenever that connection is used it will return the error that was encountered.

This is hidden by Mutex. Callers will never know why the lock is failing. This makes issues difficult to debug. For example, if redis cannot be reached you'll never see that error. Only that the lock cannot be acquired.

Proposal: return errors from commands. Simple as that. If multiple errors are encountered when operating across multiple pools, something like godoc.org/github.com/hashicorp/go-multierror could possibly be used.

Add interface for Mutex

Usally Mutex struct pass into application layer structs, that should be covered by tests. So it will be conveniently if library will provide interface

type Mutex interface {
	Lock() error
	Unlock() bool
	Extend() bool
}

Allow using just `redsync` without depending on Redis v6, v7, and Redigo

It would be great to be able to use redsync without adding all of these deps to our go.sum. Because of these deps, IDEs will autocomplete redis with the V6 version of go-redis (github.com/go-redis/redis) which is not desired.

Maybe move the version-specific packages into separate repos?

Include Usage Example

It would be great if there was a simple usage example whether on the README or godoc. Thanks

Does it work with go modules?

$ go version                      
go version go1.12.6 linux/amd64

$ export GO111MODULE=on
$ mkdir foobar && cd foobar
$ go mod init foobar
go: creating new go.mod: module foobar

$ go get gopkg.in/redsync.v1
go: gopkg.in/[email protected]: go.mod has non-....v1 module path "github.com/go-redsync/redsync" at revision v1.2.0
go: error loading module requirements

Potential bug of ValidContext/Valid

I think there is a potential bug in current implementation of ValidContext/Valid.
When ValidContext/Valid returns true, there is a possibility that the lock is expired already.
For example, case N=5, we have 3 seconds before lock expires, even if 4 nodes responds soon(~100ms) , it is possibility that the last node needs 10 seconds to respond, and if that happens, ValidContext/Valid returns true, but lock is expired.

As far as I read https://redis.io/topics/distlock, I understand we should trust only the value of until.

If the lock was acquired, its validity time is considered to be the initial validity time minus the time elapsed, as computed in step 3.

So, if #71 merged, It may be a good idea to make ValidContext/Valid deprecated and client can check by calling Until or change implementation like below to keep backward compatibility.

func (m *Mutex) Valid() (bool, error) {
	return time.Now().Before(until), nil
}

Retry Policy: Not Following The Algorithm's Criteria

In the Retry on failure section of Redlock Algorithm, it is mentioned that:

When a client is unable to acquire the lock, it should try again after a random delay in order to try to desynchronize multiple clients trying to acquire the lock for the same resource at the same time (this may result in a split brain condition where nobody wins).

While the current implementation is waiting a fixed duration of time (500 milliseconds) on lock failure.

I realized this issue while I was testing a limited number of concurrent goroutines on distributed lock. The following is a part of my test's log:

lock acquiring duration Millisecond=0
lock acquiring duration Millisecond=0.000001
lock acquiring duration Millisecond=0.000003
lock acquiring duration Millisecond=0.000005
lock acquiring duration Millisecond=0.000503
lock acquiring duration Millisecond=0.000506
lock acquiring duration Millisecond=0.000508
lock acquiring duration Millisecond=0.000505
lock acquiring duration Millisecond=0.000508
lock acquiring duration Millisecond=0.001007
lock acquiring duration Millisecond=0.001007
lock acquiring duration Millisecond=0.001007
lock acquiring duration Millisecond=0.001011
lock acquiring duration Millisecond=0.001016
lock acquiring duration Millisecond=0.001012
lock acquiring duration Millisecond=0.00151
lock acquiring duration Millisecond=0.001509
lock acquiring duration Millisecond=0.001511
lock acquiring duration Millisecond=0.001512
lock acquiring duration Millisecond=0.001516
lock acquiring duration Millisecond=0.00201
lock acquiring duration Millisecond=0.002012
lock acquiring duration Millisecond=0.002009
lock acquiring duration Millisecond=0.002013
lock acquiring duration Millisecond=0.002014
lock acquiring duration Millisecond=0.002017
lock acquiring duration Millisecond=0.002511
lock acquiring duration Millisecond=0.002511
lock acquiring duration Millisecond=0.002514
lock acquiring duration Millisecond=0.002513
lock acquiring duration Millisecond=0.002521
lock acquiring duration Millisecond=0.003018
lock acquiring duration Millisecond=0.003022
lock acquiring duration Millisecond=0.003521
lock acquiring duration Millisecond=0.003523
lock acquiring duration Millisecond=0.00402
lock acquiring duration Millisecond=0.004025
lock acquiring duration Millisecond=0.004526
lock acquiring duration Millisecond=0.004529
lock acquiring duration Millisecond=0.00503
lock acquiring duration Millisecond=0.005532
lock acquiring duration Millisecond=0.006037
lock acquiring duration Millisecond=0.006038
lock acquiring duration Millisecond=0.006541
lock acquiring duration Millisecond=0.007043
lock acquiring duration Millisecond=0.007546
lock acquiring duration Millisecond=0.008054
lock acquiring duration Millisecond=0.008553
lock acquiring duration Millisecond=0.009054
lock acquiring duration Millisecond=0.009557
lock acquiring duration Millisecond=0.010061

I have created a draft PR. I will make it ready to review as soon as I apply my tests.

Can't know which error has occurred on the mutex release

As you see in this block of code if m.releas will return error (for example NOPERM this user has no permissions to run the ‘evalsha’ command or its subcommand), we can't to know it, we will just receive a general ErrFailed error.

redsync/mutex.go

Lines 83 to 88 in 71321ce

_, _ = m.actOnPoolsAsync(func(pool redis.Pool) (bool, error) {
return m.release(ctx, pool, value)
})
}
return ErrFailed

Maybe it would be better to return this error?

For example,

_, err = m.actOnPoolsAsync(func(pool redis.Pool) (bool, error) {
    return m.release(ctx, pool, value)
})

if err != nil {
    return err
}

mutex.Lock does not aquire lock actually

My example where I used redsync + cron lib (based on goroutines):
main.go:

package main

import (
	"os"
	"os/signal"
	"myproject/pkg/crawler"
	"syscall"

	goredislib "github.com/go-redis/redis/v8"
	"github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v8"
	"github.com/robfig/cron/v3"

	flag "github.com/spf13/pflag"

	"github.com/spf13/viper"
)

func main() {
	flag.String("redisAddress", "redis:6379", "Address to redis server")
	viper.BindPFlags(flag.CommandLine)

	client := goredislib.NewClient(&goredislib.Options{
		Addr: viper.GetString("redisAddress"),
	})
	redsyncPool := goredis.NewPool(client)
	rs := redsync.New(redsyncPool)

	ctx := crawler.New(rs)

	c := cron.New(cron.WithSeconds())
	c.AddFunc("*/5 * * * * *", ctx.Crawl) // Every 5 seconds
	c.Start()

	// Wait for a signal to quit:
	signalChan := make(chan os.Signal, 1)
	// SIGTERM is called when Ctrl+C was pressed
	signal.Notify(signalChan, os.Interrupt, os.Kill, syscall.SIGTERM)
	<-signalChan

	c.Stop()
}

crawler.go

package crawler

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"time"

	"github.com/go-redsync/redsync/v4"
)

// Context is context of crawler service
type Context struct {
	Mutex  *redsync.Mutex
}

const (
	mutexName = "crawler_mutex"
)

func New(rs *redsync.Redsync) *Context {
	return &Context{
		Mutex:  rs.NewMutex(mutexName),
	}
}

func (ctx *Context) Crawl() {
	if err := ctx.Mutex.Lock(); err != nil {
		log.Println("Crawler already run")
		return
	}

	log.Println("Sleep...")
	time.Sleep(60 * time.Second) // Some Long job...
	log.Println("Woke up...")

	if ok, err := ctx.Mutex.Unlock(); !ok || err != nil {
		log.Println("Could not release crawler lock")
		return
	}
}

When I run this example I got:

crawler_1     | 2020/11/02 15:06:20 Sleep...
crawler_1     | 2020/11/02 15:06:28 Sleep...
crawler_1     | 2020/11/02 15:06:36 Sleep...
crawler_1     | 2020/11/02 15:06:44 Sleep...
crawler_1     | 2020/11/02 15:06:52 Sleep...
crawler_1     | 2020/11/02 15:07:00 Sleep...
crawler_1     | 2020/11/02 15:07:05 Crawler already run
crawler_1     | 2020/11/02 15:07:08 Sleep...
crawler_1     | 2020/11/02 15:07:10 Crawler already run
crawler_1     | 2020/11/02 15:07:15 Crawler already run
crawler_1     | 2020/11/02 15:07:16 Sleep...
crawler_1     | 2020/11/02 15:07:20 Woke up...

So mute.Lock does not aquired any lock as you see from few first lines. Maybe I'm doing something wrong?

Support for Sentinel?

Hi,

I'm using a cluster of 3 sentinels and 3 redis instances and I was wondering if redsync plans to support Sentinel automatically, or should I reach Sentinel directly before giving the master IP to this library?

Thank you,

m1.Lock() stuck for infinitely.

Run the following piece of code and observe when m.Lock() stucks for infinitely.

 package main

import (
	"fmt"
	"time"
	"github.com/go-redsync/redsync"
	"github.com/gomodule/redigo/redis"
)

const (
	RedisURL string = "redis://localhost:6379"
)

func main() {
	p := &redis.Pool{
		Dial: func() (redis.Conn, error) {
			c, err := redis.DialURL(RedisURL)
			return c, err
		},
	}
	rs := redsync.New([]redsync.Pool{p})
	option := redsync.SetExpiry(20 * time.Second)
        //Ignore RANDOM_LOCK error
	M := rs.NewMutex("RANDOM_LOCK", option)
	err := M.Lock()
	if err != nil {
		fmt.Println("Unable to aquire lock")
	}
	go thread1(rs)
	for true {

	}

}

func thread1(rs *redsync.Redsync) {
	fmt.Println("Trying to acquire lock ===> THREAD1")
	option := redsync.SetExpiry(20 * time.Second)
	m1 := rs.NewMutex("TESTLOCK", option)
	for true {
		fmt.Println("Executing...")
		err := m1.Lock()
		if err != nil {
			fmt.Println("Unable to acquire lock ==> THREAD1")
		} else {
			fmt.Println("Acquired Lock it will take 20 seconds ==> THREAD1")
		}
	}
}

Ideally, it should give some error or some explanation on the state

func acquire return value

func (m *Mutex) acquire(pool Pool, value string) bool {
conn := pool.Get()
defer conn.Close()
reply, err := redis.String(conn.Do("SET", m.name, value, "NX", "PX", int(m.expiry/time.Millisecond)))
return err == nil && reply == "OK"
}

when the function pool.Get() occur error(redis dowm or others) , but from this function i did not know the real happen ,mutex unusable or redis cant be connected ? because it return a bool value.

programmer fail, panic is "context deadline exceeded"

       client := goredislib.NewClient(&goredislib.Options{
		Addr: "localhost:6379",
	})
	pool := goredis.NewPool(client) // or, pool := redigo.NewPool(...)

	rs := redsync.New(pool)

	var wg sync.WaitGroup
	var ctx = context.Background()
	withTimeout, cancelFunc := context.WithTimeout(ctx, time.Second*10)
	defer cancelFunc()

	for i := 0; i < 5000; i++ {
		wg.Add(1)

		go func() {
			mutexname := "my-global-mutex"
			mutex := rs.NewMutex(mutexname)

			// Obtain a lock for our given mutex. After this is successful, no one else
			// can obtain the same lock (the same mutex name) until we unlock it.
			if err := mutex.Lock(); err != nil {
				panic(err)
			}

			// Do your work that requires the lock.
			productNum, err := client.HGet(withTimeout, "product_01", "product_num").Int()
			if err != nil {
				return
			}

			if productNum < 1 {
				fmt.Println("product_num < 1...")
				return
			}

			client.HIncrBy(withTimeout, "product_01", "product_num", -1)

			defer func() {
				wg.Done()
			}()

			defer func() {
				if ok, err := mutex.Unlock(); !ok || err != nil {
					panic("unlock failed")
				}
			}()
		}()
	}

	wg.Wait()

result:

 panic: 1 error occurred:
        * context deadline exceeded



goroutine 629 [running]:
main.main.func1(0xc0000ae2c0, 0xc0000d2040, 0x137e140, 0xc0000b4120, 0xc0000a2260)


Mutex lock won't lock

package Utils

import (
	"fmt"
	"github.com/go-redis/redis"
	"github.com/go-redsync/redsync"
	"log"
	"reflect"
	"strconv"
	"time"
)

var Mutex *redsync.Redsync = nil

// IsRateLimited this function you enter the ip and the amount you want to rate limit
// then the expiration for the time you want your ip to expire and it checks the and blocks ips that surpass
// the rate limit
func IsRateLimited(ip string, redisClient *redis.Client, rateLimit int, expiration time.Duration,pool interface{}) error {
	log.Println(reflect.TypeOf(pool))
	val, err := redisClient.Get(redisClient.Context(), ip).Result()
	if err != nil {
		if err == redis.Nil {
			err := redisClient.Set(redisClient.Context(), ip, 0, expiration)
			if err != nil {
				return fmt.Errorf("setting content in redis : ratelimit %w", err)
			}
		}
		return fmt.Errorf("getting content from redis : ratelimit: %w", err)
	}

	i, err := strconv.Atoi(val)
	if err != nil {
		return fmt.Errorf("strconv  : ratelimit %w", err)
	}
	if rateLimit == i {
		return fmt.Errorf("to many requests : ratelimit")
	}

	newMutex := Mutex.NewMutex(ip)
	r
	if err := newMutex.Lock(); err != nil {
		panic(err)
	}
	i++

	err = redisClient.Set(redisClient.Context(), ip, i, expiration)
	if err != nil {
		return fmt.Errorf("setting content in redis : ratelimit: %w", err)

	}
	if ok, err := newMutex.Unlock(); !ok || err != nil {
		panic("unlock failed")
	}
	return nil
}

here is my code

panic: redsync: failed to acquire lock

Tag the latest release for redsync

Could you tag the current master branch as the latest release ?
It would be v1.0.2.
When I using https://github.com/golang/dep as dependence management. It's get the latest release v1.0.1 in github as default.

Install link for Redsync not working for me

The following command given did not install Redsync for me:
$ go get gopkg.in/redsync.v1

Instead, I had to use the following command, which seems to have worked:
go get github.com/go-redsync/redsync

Is this a known problem? Was it just a problem for me? Does the README need an update?

Mutex is valid before locking it

Calling mutex.Valid() before mutex.Lock() returns true indicating mutex is acquired, but it is not.

Steps to reproduce

// ...
r := redsync.New(rdb)
mutex := r.NewMutex("test")

// we don't call mutex.Lock()

valid, err := mutex.Valid()
fmt.Println(valid, err)

Result

true nil

Expected result

false nil

Crashed in mutex.go:112

Hi, i got random crashes at mutex.go:112
this line:
defer conn.Close()

any idea why ? could that because my redis was overwhelmed by requests that getting connection from pool return nil ?

thanks!

No connection timeout

When the redis server is not available, it just keeps trying to connect forever. This should be configurable.

Redigo version

Why is redsync using github.com/gomodule/redigo v2.0.0+incompatible.

v2.0.0 branch was last updated 14 Mar 2018 and does not seem to be maintained. All new development is happening on v1 (e.g. v1.8.2 was released 8 Jun 2020).

I don't know to force my project to use redsync with [email protected] without forking redsync and fixing go.mod.

New release

Can there be a new release (that incorporates the change to gomodule/redigo)? The new Go 1.11 modules picks up the version from 2016, creating conflicting dependencies

github.com/garyburd/redigo vs github.com/gomodule/redigo

The readme states, that the only dependency is github.com/gomodule/redigo, and yet the garyburd fork implementation is used.

It seems to me that you only use that implementation so you can return an interface instead of the actual implementation. But it doesn't really help. Before you had a hard dependency on gomodule/redigo, now you have a hard dependency on garyburd/redigo. One of them has a lot of supporters and will more likely stay up to date and the other one is a fork.

Maybe it'd be better to switch back?

When first thread acquired a lock ,second thread should wait till first thread release a lock

I recently started using redsync in my go applications .I am looking for locking when first request acquired a lock and not released yet and 2nd request tried to acquire a lock it should wait or block till first request release a lock but seems like 2nd request wait for approx 6 seconds only and returns.

Is there any way to block second request till first request release a lock ?

Getting context deadline exceeded when calling Lock() function

Hello,

I'm facing this problem recently when acquiring lock. I'm not passing any context to the Lock function so is basically using the Background one.

Here you have my code:

func (rm *RedisMutexService) Mutex(key string, fn func() (interface{}, error)) (interface{}, error) {
	mutex := rm.sync.NewMutex(mutexName + key)
	defer func(mutex *redsync.Mutex) {
		rm.releaseLock(mutex)
	}(mutex)

	if err := rm.adquireLock(mutex); err != nil {
		return nil, err
	}
	return fn()
}

func (rm *RedisMutexService) releaseLock(mutex *redsync.Mutex) {
	if ok, err := mutex.Unlock(); !ok || err != nil {
		rm.logger.Error("error unlocking mutex sync", zap.Error(err))
	}
}

func (rm *RedisMutexService) adquireLock(mutex *redsync.Mutex) error {

	if err := mutex.Lock(); err != nil {
		rm.logger.Error("error locking mutex sync", zap.Error(err))
		return err
	}

	return nil
}

This is the exact message getting from error:

1 error occurred:
	* context deadline exceeded

Thanks in advance

Why 2 milliseconds is added to the expire time in the function "Lock"?

I don't understand why 2 milliseconds is added to the variable "until" in the function "Lock".
until := time.Now().Add(m.expiry - time.Now().Sub(start) - time.Duration(int64(float64(m.expiry)*m.factor)) + 2*time.Millisecond)

Based on the following post https://redis.io/topics/distlock, the safety expire time is calculated as below,
MIN_VALIDITY=TTL-(T2-T1)-CLOCK_DRIFT

So the correct formula should be as below, what did I miss?
until := time.Now().Add(m.expiry - time.Now().Sub(start) - time.Duration(int64(float64(m.expiry)*m.factor)))

History related to default `tries` value

tries: 32,

Currently, default tries value is 32.

I doubt 32 is proper default value.

I am wondering that there is any history related default tries value.

If there's no reason, how about changing default tries value?

I believe users don't expect 32 retries by default.

cluster client and pool

The pool means a redis instance? If I use redis cluster client and it has five nodes,the redis cluster is a pool or a master node is a pool.

Consider update to touchScript

redsync/mutex.go

Lines 135 to 141 in 8953834

var touchScript = redis.NewScript(1, `
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("SET", KEYS[1], ARGV[1], "XX", "PX", ARGV[2])
else
return "ERR"
end
`)

I would consider changing the touch script to be in line with the rest of the algorithm using:

var touchScript = redis.NewScript(1, `
	if redis.call("GET", KEYS[1]) == ARGV[1] then
		return redis.call("pexpire", KEYS[1], ARGV[2])
	else
		return 0
	end
`)

If pexpire attempts to set the expiry of an unset key, then it will return 0.

Installing redsync throws errors

Mac OS 10.15.4
go version go1.12.6 darwin/amd64

when I run go get github.com/go-redsync

I get the following error:
github.com/hashicorp/go-multierror
../github.com/hashicorp/go-multierror/multierror.go:112:9: undefined: errors.As
../github.com/hashicorp/go-multierror/multierror.go:117:9: undefined: errors.Is

Not quite sure what's going on I have latest redigo.

v1.4.1 not following semver

According to semver.org updating MINOR version should be made when "you add functionality in a backwards compatible manner" and if you are making breaking changes you must update MAJOR version.

In commit fb51a7f the signature for Unlock() got changed which means that it introduces a breaking change. I noticed this while updating dependencies for an application using a third party library which in turn is using redisync. If you're not the author of every package in the dependency chain this means that you can no longer run go get -u all to update your dependencies.

I suggest releasing a v1.4.2 tag from 98bb566 and then bump this library to v2.0.0 and create a new release with the new signature from master.

Do not make "github.com/gomodule/redigo/redis" as a dep?

Hello

I think make "github.com/gomodule/redigo/redis" as a hard dep is ok, but not flexible.

You can design a interface which demand the app to implement some redis func to complete the lock job. And still, you can use "github.com/gomodule/redigo/redis" to implement a example for the interface.

Thanks

Question regarding nodem (sync.Mutex)

m.nodem.Lock()

I am confused as to why a sync.Mutex is needed. Is it the case that the same Mutex struct pointer might be passed between goroutines? If this is a concern, I would argue it is an anti-pattern to do that in implementation.

I bring it up because it is an unnecessary overhead if it is in fact an existential safety precaution.

Remove (indirect) dependency on `garyburd/redigo`

The go.mod file still references garyburd. This is an indirect reference from github.com/stvp/tempredis

Using modules I can't go get the v1.1.0 release since the garyburd repo is now archived and not being updated. It doesn't have a v2.0.0 tag.

go get github.com/go-redsync/[email protected]
go: finding github.com/garyburd/redigo v2.0.0+incompatible
go: github.com/garyburd/[email protected]+incompatible: unknown revision v2.0.0
go: error loading module requirements

I've made a PR to fix stvp/tempredis
stvp/tempredis#2

Dependencies issues "github.com/garyburd/redigo/redis"

Hi everyone,

I see that the "github.com/garyburd/redigo/redis" dependencies is not anymore in the redsync code and has been replace by the gomodule one. But it does not seem to be released.

Do you have any idea when it will be the case?
It is still causing some issue on my side:

D:\dev\go\pkg\mod\github.com\garyburd\[email protected]+incompatible\redis\pool.go:28:2: use of internal package github.com/gomodule/redigo/internal not allowed

Thanks in advance! 👍

@hjr265

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.