Duality is a simple cache helper for using multiple caches. The idea is that you have local cache and a shared cache -- or fast and slow cache -- and want to save to both, and read from local, if present and shared if not. The idea came from Hector Virgen (the PHP Zend Jedi Ninja Badass) and Zend_Cache_Backend_TwoLevels, which does basically the same thing in PHP.

A few things to note:

  • It currently implements the methods of my other two cache projects -- Diskcached and Monogocached, both which take their implementation from the popular Memcached.
  • I'm working on a Rails implementation, which uses ActiveSupport::Cache::Store -- more to come on that later. I haven't had time to work on this, contributions are welcome.
  • My origional intent was to make sets asynchronous, but benchmarking shows that to be less efficent due either to my lack of knowledge in threaded development, or -- based on what I'm reading -- ruby inefficenies in threading.


gem install duality

Or via bundler:

# file: Gemfile
source :rubygems
gem 'duality'

Basic Usage

require 'diskcached'
require 'mongocached' # or memcached if you prefer
require 'duality'

$cache = Dulatiy.new(Diskcached.new, Mongocached.new( host: 'remotehost' ))

# cache something
$cache.set('cache_key', 'cache_content')

# get cache
puts $cache.get('cache_key') # => cache_content

# delete something

# flush cache

Unimplemented Cache Methods

One thing Duality does for compatability is pass methods via #method_missing. This allows for you to access any method your cache might implement, even if Duality doesn't itself implement it.

It's important to note, though, that the this implementation does not take advantage of the get methods speed increase by returning the faster cache first, but will perform the action in a serialized fashion on one cache, then the other. Additionally, by default, it will return the value of whichever cache works, meaning that if one raises and exception, returns false or nil, but the other returns successfully, it will return the successful result. This is by design.

To force both caches to "be good or die", I've implemented strict calls, where by you can prepend "strict_" to any method call which you know Duality doesn't implement and force it to fail if both caches don't return a valid result.

Another thing that's worth mentioning is if either cache raise an exception, it will be caught. If both caches raise an exception, nil will be returned. Also, if both caches return nil, nil will be returned.

# when only one cache contains requested method

# => returns implementing caches return value

# => raises no method exception

# when both caches contains requested method

# => returns best match

# => returns best match

More Info