Lock automatically releases after some time.
qburst-ambareeshb opened this issue · comments
I compiled the code that actually locks a RedisClient for ten seconds, Ran two instances of the same code. So for same locking key I got error for a couple of times. Interestingly I after some attempts I could gain the lock while the older instance did not release the lock it has acquired (for 10 seconds). Is it the desired behavior?
I might have run into something similar, I have 2 apps running the same code using Redis lock. Most of the time, lock works but noticed if I send messages to the app quickly, both instances gain lock and execute the code even though only one instance should be able to gain lock at a time.
@Rizbe interesting, we have been using this package internally and never had this issue. Would you be able to recreate it in a test somehow? Is it very frequent?
Basically the doubt is, I have a program that creates a new redisClient and try to acquire lock with lock := lock.New(redis.Client, key, &opts)
and then calling lock.Lock()
. then wait for 10s and call lock.Unlock().
If I run the code twice does both calls to lock.Lock() succeed? in my case it does but I don't want to.
Sorry, I don't really understand the problem here, I've written a really short script to demonstrate the functionality:
package main
import (
"context"
"log"
"time"
"github.com/bsm/redis-lock"
"github.com/go-redis/redis"
"golang.org/x/sync/errgroup"
)
func main() {
if err := run(context.Background()); err != nil {
log.Fatalln(err)
}
}
func run(ctx context.Context) error {
client := redis.NewClient(&redis.Options{
Network: "tcp",
Addr: "127.0.0.1:6379",
})
defer client.Close()
n := 0
group, ctx := errgroup.WithContext(ctx)
group.Go(func() error {
locker := lock.New(client, "lock.foo", nil)
for i := 0; i < 100; {
if mine, err := locker.LockWithContext(ctx); err != nil {
return err
} else if mine {
n++
i++
if err := locker.Unlock(); err != nil {
return err
}
}
time.Sleep(10 * time.Millisecond)
}
return nil
})
group.Go(func() error {
locker := lock.New(client, "lock.foo", nil)
for i := 0; i < 90; {
if mine, err := locker.LockWithContext(ctx); err != nil {
return err
} else if mine {
n++
i++
if err := locker.Unlock(); err != nil {
return err
}
}
time.Sleep(9 * time.Millisecond)
}
return nil
})
if err := group.Wait(); err != nil {
return err
}
log.Printf("N=%d", n)
return nil
}
For me, it outputs: N=190
, as expected.
Equally, if I run:
package main
import (
"context"
"log"
"time"
"github.com/bsm/redis-lock"
"github.com/go-redis/redis"
)
func main() {
if err := run(context.Background()); err != nil {
log.Fatalln(err)
}
}
func run(ctx context.Context) error {
client := redis.NewClient(&redis.Options{
Network: "tcp",
Addr: "127.0.0.1:6379",
})
defer client.Close()
locker := lock.New(client, "lock.foo", nil)
if mine, err := locker.LockWithContext(ctx); err != nil {
return err
} else if mine {
log.Println("the lock is mine")
}
time.Sleep(8 * time.Second)
return locker.Unlock()
}
I get:
2018/10/12 10:38:07 the lock is mine
2018/10/12 10:38:15 lock unlock failed
exit status 1
Also fully expected!
The default lock timeout is set to 5s in the options (see https://godoc.org/github.com/bsm/redis-lock#Options). If you want to lock something for 10s, you must extend the LockTimeout
accordingly, ideally with some additional grace time. Hope that helps.
Got it, One doubt is what if I don't need time out or literally lock until I call Unlock
.
There should always be some sort of timeout on a lock. Just set it really high, e.g. several hours/days/weeks/years :)
Ok thanks for replying.