Redify

Dependency Status Code Climate

State of Code

Redify is currently under development and is not ready for public usage yet.

Introduction

Redify intends to act as a plug-and-play Redis layer for your ActiveRecord models. By adding the following to your models...

class Foo < ActiveRecord::Base
  redify
  # ... rest of your code ...
end

... a few common database operations will be done through Redis instead of ActiveRecord, increasing overall speed of queries and decreasing your database server access frequency.

Considerations

Redify will increase your server memory usage, depending on data size that is stored into Redis. It will also likely increase the boot time of your application, since Redify loads all data into Redis upon model initialization. Please keep those in mind when using this gem.

Requirements

Instead of directly connecting into Redis itself, Redify requires an already connected handler that responds to Redis commands (like get, hmget, etc), so it is not restricted to a specific Redis client.

It works best with models which primary keys are either numeric or strings without any special characters, since they are used to compose key names in Redis.

Redify requires ActiveSupport ~> 3.0.

Installation

Add this line to your application's Gemfile:

gem 'redify', :git => 'git://github.com/pauloddr/redify.git'

And then execute:

$ bundle

Or install it yourself as:

$ gem install redify

Setting Up

You can set up default options in Redify::Settings in your initializer scripts. The following example assumes you have defined a $redis variable elsewhere in your application pointing to a handler that responds to Redis commands:

Redify::Settings.default_handler = $redis

You can define a namespace to be prepended to every key handled by Redify. By default, this namespace equals to "Redify" unless you set this option. A couple examples for Rails applications:

# MyApplication:production:*
Redify::Settings.namespace = "#{Rails.application.name}:#{Rails.env}"

# MyApplication:1.2.0:*
Redify::Settings.namespace = "#{Rails.application.name}:#{Rails.configuration.assets.version}" 

Redis Structure

Considering a model called User and an empty namespace, Redify will automatically generate the following keys in Redis when you "redify" a model:

  • Users - a hash with extended data about the model with the following fields:
    • field_names - a string with a comma-separated, ordered list of field names.
    • field_types - a string with a comma-separated, ordered list of field types. Possible values are: string, number, float, date, datetime and boolean.
    • associations - a string with a comma-separated list of associations that are "redified' for the model.
    • redify_status - internal status of model "redification". Possible values are "LOADING" and "READY".
  • Users:All - an ordered list of primary keys from Users.
  • User:N (for each record) - an hash containing information about a single record, where N is the record primary key.

When you throw in an associated model called Post, where user has_many posts, you also get:

  • Posts
  • Posts:All
  • Post:N (for each record)
  • User:N:Posts (for each User) - an ordered list of Post IDs that belong to User#N.

Operations

Redify will use Redis for the following common operations:

  • User.all
  • User.find N
  • User.first(n) and User.last(n)
  • User#Posts (associations)

Redify will fall back to ActiveRecord on more complex queries until it works with more finders and options.

Initialization Options

Upon "redification" of a model, you can pass some extended options.

:with_associations => [...]

class User < ActiveRecord::Base
  has_many :posts
  redify :with_associations => [:posts]
  # ...
end

You can also pass :all instead of an array of associations to always redify all associations.

:through => <redis_handler>

Redify will use the default Redis handler passed to Redify::Settings.default_handler unless you specify this option. Namespace rules still apply to all Redis instances in use.

Finder Options

:skip_redify => true

Example:

User.all :skip_redify => true

Use this option if for some reason you want to go straight to ActiveRecord.

:as => :hash

Example:

User.all :as => :hash

Redify will return raw hashes instead of ActiveRecord models. This will yield the fastest speeds. Use this if you can affort not relying on ActiveRecord instances.

If the model has any redified associations, they will be available as an array of IDs. For example, when an user has many posts and they're included in the query (as in, :include => :posts), its hash will return as:

{id: 1, name: "...", ..., post_ids: [1, 2, 3,...]}

Scalability and Maintenance

Redify is intended to work with multiple servers running multiple spawns of the same application, all sharing the same Redis connection. Data integrity is kept tight through a solid namespace composition and some under-the-hood work (keep reading) within the gem. That way, Redis can work as a large pool of data serving multiple applications in the same or different servers.

To make sure multiple instances don't interfere with each other, Redify sets a root-level namespace in Redis called RedifyApps, followed by the server hostname, and finally the application namespace. This structure is then used to keep track of all processes running Redify applications. It maintains itself on demand by running a sanity check upon application boot, deleting old keys from applications that are no longer being used by any active processes.

Wishlist (TODO)

In no particular order...

  • make it work with more finders
  • implement a simple index system with tags (a.k.a. "poor man's elastic search")

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request