1// Copyright 2013 Gary Burd 2// 3// Licensed under the Apache License, Version 2.0 (the "License"): you may 4// not use this file except in compliance with the License. You may obtain 5// a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12// License for the specific language governing permissions and limitations 13// under the License. 14 15package redis_test 16 17import ( 18 "fmt" 19 "github.com/garyburd/redigo/redis" 20) 21 22// zpop pops a value from the ZSET key using WATCH/MULTI/EXEC commands. 23func zpop(c redis.Conn, key string) (result string, err error) { 24 25 defer func() { 26 // Return connection to normal state on error. 27 if err != nil { 28 c.Do("DISCARD") 29 } 30 }() 31 32 // Loop until transaction is successful. 33 for { 34 if _, err := c.Do("WATCH", key); err != nil { 35 return "", err 36 } 37 38 members, err := redis.Strings(c.Do("ZRANGE", key, 0, 0)) 39 if err != nil { 40 return "", err 41 } 42 if len(members) != 1 { 43 return "", redis.ErrNil 44 } 45 46 c.Send("MULTI") 47 c.Send("ZREM", key, members[0]) 48 queued, err := c.Do("EXEC") 49 if err != nil { 50 return "", err 51 } 52 53 if queued != nil { 54 result = members[0] 55 break 56 } 57 } 58 59 return result, nil 60} 61 62// zpopScript pops a value from a ZSET. 63var zpopScript = redis.NewScript(1, ` 64 local r = redis.call('ZRANGE', KEYS[1], 0, 0) 65 if r ~= nil then 66 r = r[1] 67 redis.call('ZREM', KEYS[1], r) 68 end 69 return r 70`) 71 72// This example implements ZPOP as described at 73// http://redis.io/topics/transactions using WATCH/MULTI/EXEC and scripting. 74func Example_zpop() { 75 c, err := dial() 76 if err != nil { 77 fmt.Println(err) 78 return 79 } 80 defer c.Close() 81 82 // Add test data using a pipeline. 83 84 for i, member := range []string{"red", "blue", "green"} { 85 c.Send("ZADD", "zset", i, member) 86 } 87 if _, err := c.Do(""); err != nil { 88 fmt.Println(err) 89 return 90 } 91 92 // Pop using WATCH/MULTI/EXEC 93 94 v, err := zpop(c, "zset") 95 if err != nil { 96 fmt.Println(err) 97 return 98 } 99 fmt.Println(v) 100 101 // Pop using a script. 102 103 v, err = redis.String(zpopScript.Do(c, "zset")) 104 if err != nil { 105 fmt.Println(err) 106 return 107 } 108 fmt.Println(v) 109 110 // Output: 111 // red 112 // blue 113} 114