Frivol - Frivolously simple temporary storage backed by Redis
A really simple Redis-backed temporary storage mechanism intended to be used with ActiveRecord, but will work with other ORM’s or any classes really.
I developed Frivol secifically for use in Mad Mimi (madmimi.com) to help with caching of data which requires fairly long running (multi-second) database queries, and also to help with communication of status from background tasks running in Resque on workers to the front end web servers. Redis was chosen because we already had Resque, which is Redis-backed. Also, unlike memcached, Redis persists it’s data to disk, meaning there is far less warmup required when a hot system is restarted. Frivol’s design is such that it solves our problem, but I believe it is generic enough to be used in many Rails web projects and even in other types of projects altogether.
Usage
Configure Frivol in your configuration, for example in an initializer or in environment.rb
REDIS_CONFIG = {
:host => "localhost",
:port => 6379
}
Frivol::Config.redis_config = REDIS_CONFIG
Now include Frivol in whichever classes you’d like to make use of temporary storage. You can optionally call the storage_expires_in(time)
class method to set a default expiry. In your methods you can now call the store(keys_and_values)
and retrieve(keys_and_defaults)
methods.
Defaults in the retrieve
method can be symbols, in which case Frivol will check if the class respond_to?
a method by that name to get the default.
The expire_storage(time)
method can be used to set the expiry time in seconds of the temporary storage. The default is not to expire the storage, in which case it will live for as long as Redis keeps it.
Frivol uses the storage_key
method to create a base key for storage in Redis. The current implementation uses "#{self.class.name}-#{id}"
so you’ll want to override that method if you have classes that don’t respond to id.
Frivol also extends Time to allow it to be (de)serialized to JSON, which currently used to store data in Redis.
Example
class BigComplexCalcer
include Frivol
storage_expires_in 600 # temporary storage expires in 10 minutes.
def initialize(key)
@key = key
end
def storage_key
"frivol-test-#{key}" # override the storage key because we don't respond_to? id
end
def big_complex_calc
retrieve :complex => :do_big_complex_calc # do_big_complex_calc is the method to get the default from
end
def last_calc_done
last = retrieve :last => nil # default is nil
return "never" if last.nil?
return "#{Time.now - last} seconds ago"
end
def do_big_complex_calc
# Wee! Do some really hard work here...
# ...still working...
store :complex => result, :last => Time.now # ...and let's keep the result for at least 10 minutes, as well as the last time we did it
end
end
Note on Patches/Pull Requests
-
Fork the project.
-
Make your feature addition or bug fix.
-
Add tests for it. This is important so I don’t break it in a future version unintentionally.
-
Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
-
Send me a pull request. Bonus points for topic branches.
Copyright
Copyright © 2010 Marc Heiligers. See LICENSE for details.