bsm / redis-lock

[DEPRECATED] Please see https://github.com/bsm/redislock instead

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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?

commented

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.