Ruby Goldberg machines are deliberately complex contraptions that require the designer to perform a series of excessively convoluted steps to accomplish a very simple task (turn on a light switch). In my career I worked on some applications that also were a little too complex.

For “fun” exercise we will build a system using Redis performing a simple task such as writing something to a log file. Except to make it more interesting we will push data through multiple Redis data structures.

If we did not need to push data through Redis we would have a simple class in our Ruby on Rails application that wrote to a log file.

class RedisRubeGoldberg
  def perform input
    # some code here
    Rails.logger.info input
  end
end

To make out code work with Redis we will modify it like this. We will create a @uuid which will be used as various Redis keys. Then we will call methods such as string and list to read/write data from different Redis data structures. At the end we will grab data from the last data structure (in this case sorted_set) and actually write it to a log file.

# config/initializers/redis.rb
REDIS = Redis.new host: 'localhost', ...
class RedisRubeGoldberg
  def initialize
    @uuid = SecureRandom.uuid
  end
  def perform input
    string input
    list
    hash
    set
    sorted_set
    output
  end
private
  def string input
    ...
  end
  ...
end

String

Here we use a basic set command to write data to a key @uuid with value of input. We have to pass input to the method but in the future methods we will get it from Redis. We are also logging method name so we can verify our program execution through all the steps.

def string input
  Rails.logger.info __method__
  REDIS.set @uuid, input
end
# data in Redis
{"key":"444c337c-04fc-41f8-8a2e-92b05e347ca7","ttl":-1,"type":"string",
  "value":"input string",...}

List

We use get operation to read the data from Redis String. Then we remove the @uuid key otherwise we will not be able to create a new record with the same key. And finally we do lpush to insert data into a Redis List.

def list
  Rails.logger.info __method__
  data = REDIS.get @uuid
  REDIS.del @uuid
  REDIS.lpush @uuid, data
end
# data in Redis
{"key":"444c337c-04fc-41f8-8a2e-92b05e347ca7","ttl":-1,"type":"list",
  "value":["input string"],...}

Hash

We are following similar pattern of getting data out of Redis only now we are using rpop command. Once the last item is removed from Redis List that key will be deleted so we do not need to call REDIS.del but there is no harm in doing it. Then we insert it into Hash specifying ‘data’ string as the field and data variable as the value.

def hash
  Rails.logger.info __method__
  data = REDIS.rpop @uuid
  REDIS.del @uuid
  REDIS.hset @uuid, 'data', data
end
# data in Redis
{"key":"444c337c-04fc-41f8-8a2e-92b05e347ca7","ttl":-1,"type":"hash",
  "value":{"data":"input string"},...}

Set

We extract data from Redis Hash using hget, delete the key and add the same data to Set with sadd command.

def set
  Rails.logger.info __method__
  data = REDIS.hget @uuid, 'data'
  REDIS.del @uuid
  REDIS.sadd @uuid, data
end
# data in Redis
{"key":"444c337c-04fc-41f8-8a2e-92b05e347ca7","ttl":-1,"type":"set",
  "value":["input string"],...}

Sorted Set

Since we know that our Redis Set has only one member we can call .first on the results of smembers command. We use zadd command and specify epoch time as the member score.

def sorted_set
  Rails.logger.info __method__
  data = REDIS.smembers(@uuid).first
  REDIS.del @uuid
  REDIS.zadd @uuid, Time.now.to_i, data
end
# data in Redis
{"key":"444c337c-04fc-41f8-8a2e-92b05e347ca7","ttl":-1,"type":"zset",
  "value":[["input string",1522815643.0]],...}

In the output method we get data out of Redis with zrange command and finally write it to a log file.

def output
  Rails.logger.info __method__
  data = REDIS.zrange(@uuid, 0, -1).first
  REDIS.del @uuid
  Rails.logger.info data
end

Obviously this is a crazy exercise but it does illustrate a point of how can we store data in Redis data structures. And now for something more fun here are YouTube videos of real Rube Goldberg machines.

  • https://en.wikipedia.org/wiki/Rube_Goldberg_machine
  • https://www.rubegoldberg.com
  • https://redis.io