Pipelines and transactions

Learn how to use Redis pipelines and transactions

Redis lets you send a sequence of commands to the server together in a batch. There are two types of batch that you can use:

  • Pipelines avoid network and processing overhead by sending several commands to the server together in a single communication. The server then sends back a single communication with all the responses. See the Pipelining page for more information.
  • Transactions guarantee that all the included commands will execute to completion without being interrupted by commands from other clients. See the Transactions page for more information.

Execute a pipeline

To execute commands in a pipeline with redis-rb, call pipelined() and queue commands in the block. Redis executes them as a batch and pipelined() returns the results in order:

Foundational: Use pipelined to batch multiple commands together and reduce network round trips
r.pipelined do |pipe|
  (0..4).each { |i| pipe.set("seat:#{i}", "##{i}") }
end

seats = r.pipelined do |pipe|
  pipe.get('seat:0')
  pipe.get('seat:3')
  pipe.get('seat:4')
end

puts seats[0] # >>> #0
puts seats[1] # >>> #3
puts seats[2] # >>> #4

Execute a transaction

Transactions use multi(). Commands queued inside the block run atomically when the block finishes, and multi() returns the results in order:

Foundational: Use multi to execute multiple commands atomically without interruption from other clients
trans_results = r.multi do |tx|
  tx.incrby('counter:1', 1)
  tx.incrby('counter:2', 2)
  tx.incrby('counter:3', 3)
end

puts trans_results[0] # >>> 1
puts trans_results[1] # >>> 2
puts trans_results[2] # >>> 3

Watch keys for changes

Redis supports optimistic locking to avoid inconsistent updates to keys that several clients may modify at the same time. The basic idea is to watch for changes to any keys that you use in a transaction while you are preparing the update. If the watched keys do change, the transaction returns nil and you must retry using the latest value from Redis. See Transactions for more information about optimistic locking.

The example below watches a key, reads its current value, and then updates it inside multi():

Optimistic locking: Use watch with multi and retry when another client modifies the watched key
r.set('shellpath', '/usr/syscmds/')

# Watch the key, read its current value, then queue the update in a
# transaction. `multi` returns `nil` if the watched key changed before
# `EXEC` ran, in which case you would retry with the latest value.
result = r.watch('shellpath') do |client|
  current_path = client.get('shellpath')
  new_path = current_path + ':/usr/mycmds/'

  client.multi do |tx|
    tx.set('shellpath', new_path)
  end
end

if result.nil?
  puts 'Transaction aborted; retry with the latest value'
else
  puts r.get('shellpath')
  # >>> /usr/syscmds/:/usr/mycmds/
end
RATE THIS PAGE
Back to top ↑