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:
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
require 'redis'
r = Redis.new
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
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
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
Execute a transaction
Transactions use multi(). Commands queued inside the block run atomically
when the block finishes, and multi() returns the results in order:
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():
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