├── README.md └── lock.go /README.md: -------------------------------------------------------------------------------- 1 | # go_redis_lock 2 | -------------------------------------------------------------------------------- /lock.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "time" 7 | 8 | "github.com/garyburd/redigo/redis" 9 | ) 10 | 11 | type Lock struct { 12 | resource string 13 | token string 14 | conn redis.Conn 15 | timeout int 16 | } 17 | 18 | func (lock *Lock) tryLock() (ok bool, err error) { 19 | _, err = redis.String(lock.conn.Do("SET", lock.key(), lock.token, "EX", int(lock.timeout), "NX")) 20 | if err == redis.ErrNil { 21 | // The lock was not successful, it already exists. 22 | return false, nil 23 | } 24 | if err != nil { 25 | return false, err 26 | } 27 | return true, nil 28 | } 29 | 30 | func (lock *Lock) Unlock() (err error) { 31 | _, err = lock.conn.Do("del", lock.key()) 32 | return 33 | } 34 | 35 | func (lock *Lock) key() string { 36 | return fmt.Sprintf("redislock:%s", lock.resource) 37 | } 38 | 39 | func (lock *Lock) AddTimeout(ex_time int64) (ok bool, err error) { 40 | ttl_time, err := redis.Int64(lock.conn.Do("TTL", lock.key())) 41 | if err != nil { 42 | log.Fatal("redis get failed:", err) 43 | } 44 | if ttl_time > 0 { 45 | _, err := redis.String(lock.conn.Do("SET", lock.key(), lock.token, "EX", int(ttl_time+ex_time))) 46 | if err == redis.ErrNil { 47 | return false, nil 48 | } 49 | if err != nil { 50 | return false, err 51 | } 52 | } 53 | return false, nil 54 | } 55 | 56 | func TryLock(conn redis.Conn, resource string, token string, DefaulTimeout int) (lock *Lock, ok bool, err error) { 57 | return TryLockWithTimeout(conn, resource, token, DefaulTimeout) 58 | } 59 | 60 | func TryLockWithTimeout(conn redis.Conn, resource string, token string, timeout int) (lock *Lock, ok bool, err error) { 61 | lock = &Lock{resource, token, conn, timeout} 62 | 63 | ok, err = lock.tryLock() 64 | 65 | if !ok || err != nil { 66 | lock = nil 67 | } 68 | 69 | return 70 | } 71 | 72 | func main() { 73 | fmt.Println("start") 74 | DefaultTimeout := 10 75 | conn, err := redis.Dial("tcp", "localhost:6379") 76 | 77 | lock, ok, err := TryLock(conn, "xiaoru.cc", "token", int(DefaultTimeout)) 78 | if err != nil { 79 | log.Fatal("Error while attempting lock") 80 | } 81 | if !ok { 82 | log.Fatal("bug") 83 | } 84 | lock.AddTimeout(100) 85 | 86 | time.Sleep(time.Duration(DefaultTimeout) * time.Second) 87 | fmt.Println("end") 88 | defer lock.Unlock() 89 | } 90 | --------------------------------------------------------------------------------