6

I have previously been using this:

data, err := redis.Bytes(c.Do("GET", key))

to make sure that data returned is a slice of bytes.

However, I now need to add an extra command to the Redis request so I have something like this:

c.Send("MULTI")
c.Send("GET", key)
c.Send("EXPIRE", key)
r, err := c.Do("EXEC")

but now I can't seem to make the GET command return a slice of bytes. I've tried adding redis.Bytes like below but no luck.

c.Send("MULTI")
redis.Bytes(c.Send("GET", key))
c.Send("EXPIRE", key)
r, err := c.Do("EXEC")
tommyd456
  • 10,443
  • 26
  • 89
  • 163

2 Answers2

6

In redis, the EXEC command returns an array containing the results of all the commands in the transaction.

redigo provides a Values function, which converts an array command reply to a []interface{}.

c.Send("MULTI")
c.Send("GET", key)
c.Send("EXPIRE", key)
r, err := redis.Values(c.Do("EXEC"))

r[0] now has the reply from your GET command as a interface{}, so you'll need to do a type assertion to get the slice of bytes you're expecting:

data := r[0].([]byte)

References

wyattisimo
  • 2,416
  • 2
  • 20
  • 18
  • Note that if you are not very familiar with the internals of redis and redigo, it might be safer to also use the built in conversion functions with a nil error value for the secondary conversions. In this example, that would look like this: `data := redis.Bytes(r[0], nil)`. – GrandOpener Jul 31 '17 at 20:22
4

MULTI is used to send several commands in an atomic way to Redis, by creating a transaction. This is not a pipeline at all.

None of the commands will be actually executed before the EXEC call so it is impossible to obtain the value when you call GET from within a transaction.

From the docs:

When a Redis connection is in the context of a MULTI request, all commands will reply with the string QUEUED (sent as a Status Reply from the point of view of the Redis protocol). A queued command is simply scheduled for execution when EXEC is called.

In redigo pipelining is done in a different way:

http://godoc.org/github.com/garyburd/redigo/redis#hdr-Pipelining

What you want to do is something like this (untested):

c.Send("GET", key)
c.Send("EXPIRE", key)
c.Flush()
v := redis.Bytes(c.Receive()) // reply from GET
_, err = c.Receive() // reply from EXPIRE
SirDarius
  • 41,440
  • 8
  • 86
  • 100
  • Yeah good point - changed title to something more appropriate. – tommyd456 May 29 '15 at 08:59
  • I disagree with your remark about modifications. Read consistency is as important as write consistency, and a Redis MULTI/EXEC block can ensure both. There are definitely use cases for which you need to use GET operations in a MULTI/EXEC block. – Didier Spezia May 29 '15 at 11:52
  • @SirDarius It *is* possible to get the results from commands in a transaction. See my answer. – wyattisimo Dec 02 '15 at 03:05
  • @wyattisimo I said from **within** a transaction. Your answer obtains the values after the transaction has been executed, just like mine, except in a better way. `Values` is nicer than the `Receive` calls indeed. – SirDarius Dec 02 '15 at 09:41