Multi Redis

Pattern to execute separate redis-rb operations in the same command pipeline or multi/exec.

Gem Version Dependency Status Build Status Coverage Status

Installation

Put this in your Gemfile:

gem 'multi_redis', '~> 0.1.0'

Then run bundle install.

Usage

Assume you have two separate methods that call redis:

$redis = Redis.new
$redis.set 'key1', 'foo'
$redis.set 'key2', 'bar'

class MyRedisClass

  def do_stuff
    $redis.get 'key1'
  end

  def do_other_stuff
    $redis.get 'key2'
  end
end

o = MyRedisClass.new
o.do_stuff         #=> "foo"
o.do_other_stuff   #=> "bar"

This works, but the redis client executes two separate requests to the server, and waits for the result of the first one to start the second one:

Request 1:
- GET key1

Request 2:
- GET key2

redis-rb allows you to run both in the same command pipeline:

results = $redis.pipelined do
  $redis.get 'key1'
  $redis.get 'key2'
end

results[0]   #=> "foo"
results[1]   #=> "bar"

But it would be hard to refactor the two methods to use a pipeline while still keeping them separate.

Multi Redis provides a pattern to structure this code so that your separate redis calls may be executed together in one request when needed.

$redis = Redis.new
$redis.set 'key1', 'foo'
$redis.set 'key2', 'bar'

# Create a redis operation, i.e. an operation that performs redis calls, for the first method.
do_stuff = MultiRedis::Operation.new do

  # Pipelined blocks will be run in a command pipeline.
  # All redis commands will return futures inside this block, so you can't use the values immediately.
  pipelined do |mr|
    $redis.get 'key1'
  end

  # This run block will be executed after the pipelined block is completed and all futures have been resolved.
  # The #last_replies method of the Multi Redis context will return the results of all redis calls in the pipelined block.
  run do |mr|
    mr.last_replies[0]   # => "foo"
  end
end

# The return value of the operation is that of the last block.
result = do_stuff.execute   #=> "foo"

# Create the redis operation for the other method.
do_other_stuff = MultiRedis::Operation.new do

  multi do |mr|
    $redis.get 'key2'
  end

  run do |mr|
    mr.last_replies[0]   #=> "bar"
  end
end

result = do_other_stuff.execute   #=> "bar"

The two operations can still be executed separately like before, but they can also be combined through Multi Redis:

MultiRedis.execute do_stuff, do_other_stuff

Both redis calls get grouped into the same command pipeline:

One request:
- GET foo
- GET bar

The array of results is returned by the execute call:

MultiRedis.execute do_stuff, do_other_stuff   #=> [ "foo", "bar" ]

Meta

  • Author: Simon Oulevay (Alpha Hydrae)
  • License: MIT (see LICENSE.txt)