Frivol -  Frivolously simple temporary storage backed by Redis <ul><li>Marc Heiligers (@marcheiligers) </li></ul><ul><ul><...
Future Development
Lessons Learnt </li></ul></ul>
Why Frivol? <ul><li>Why the name? </li><ul><li>Every technology needs a cool name
I searched
Antonym of  save  or  put aside , actually </li></ul></ul><ul><li>Why the technology? </li><ul><li>Already had Resque
Uses Redis which is  fast  and  persistent
Allows expiry of aging data
Great for caching </li></ul></ul>
Upcoming SlideShare
Loading in...5

Frivol Ruby on Beer talk, Sept 2010


Published on

  • Be the first to comment

  • Be the first to like this

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Frivol Ruby on Beer talk, Sept 2010

  1. 1. Frivol - Frivolously simple temporary storage backed by Redis <ul><li>Marc Heiligers (@marcheiligers) </li></ul><ul><ul><li>Why Frivol?
  2. 2. Usage
  3. 3. Implementation
  4. 4. Problems
  5. 5. Future Development
  6. 6. Lessons Learnt </li></ul></ul>
  7. 7. Why Frivol? <ul><li>Why the name? </li><ul><li>Every technology needs a cool name
  8. 8. I searched
  9. 9. Antonym of save or put aside , actually </li></ul></ul><ul><li>Why the technology? </li><ul><li>Already had Resque
  10. 10. Uses Redis which is fast and persistent
  11. 11. Allows expiry of aging data
  12. 12. Great for caching </li></ul></ul>
  13. 13. Usage <ul><li>Intended to be used with ActiveRecord
  14. 14. Set Frivol::Config.redis_config= in environment.rb
  15. 15. include Frivol or Frivol::Config.include_in
  16. 16. Simply use store and retrieve methods
  17. 17. Stored keys are merged, not overwritten
  18. 18. expire_storage and delete_storage
  19. 19. Override storage_key if not using ActiveRecord </li></ul>
  20. 20. Usage – Example from Mad Mimi # environment.rb # Each environment has a REDIS_CONFIG, eg. development.rb: # REDIS_CONFIG = { :host => &quot;localhost&quot;, :port => 6379 } Frivol::Config.redis_config = REDIS_CONFIG # Frivol could be included in all AR models using: # Frivol::Config.include_in ActiveRecord::Base, 10.minutes # audience_list.rb class AudienceList < ActiveRecord::Base include Frivol storage_expires_in has_many :memberships, :dependent => :destroy has_many :audience_members, :through => :memberships # ... def list_size retrieve :list_size => :force_list_size_update end def force_list_size_update new_size = audience_members.size store :list_size => new_size new_size end # ... end
  21. 21. Implementation <ul><li>Frivol is a Module which is included
  22. 22. Uses Module#included (class methods)
  23. 23. Has helper methods separated (privacy) </li><ul><li>instance_variable_defined? , instance_variable_get and instance_variable_set </li></ul><li>Config module creates @@redis when given a Redis configuration (lifetime)
  24. 24. Resolves symbols vs strings for keys
  25. 25. Json storage (network latency) </li></ul>
  26. 26. Implementation – Config & Included module Config def self.redis_config=(config) @@redis = end def self.redis @@redis end def self.include_in(host_class, storage_expires_in = nil) host_class.send(:include, Frivol) host_class.storage_expires_in storage_expires_in if storage_expires_in end end module ClassMethods def storage_expires_in(time) @frivol_storage_expiry = time end def storage_expiry @frivol_storage_expiry end end def self.included(host) host.extend(ClassMethods) end
  27. 27. Implementation - Helpers module Helpers def self.store_hash(instance) hash = instance.instance_variable_get(:@frivol_hash) is_new = instance.instance_variable_get(:@frivol_is_new) key = instance.send(:storage_key) Frivol::Config.redis[key] = hash.to_json if is_new instance.expire_storage instance.class.storage_expiry instance.instance_variable_set :@frivol_is_new, false end end def self.retrieve_hash(instance) return instance.instance_variable_get(:@frivol_hash) => if instance.instance_variable_defined? :@frivol_hash key = instance.send(:storage_key) json = Frivol::Config.redis[key] instance.instance_variable_set :@frivol_is_new, json.nil? hash = json.nil? ? {} : JSON.parse(json) instance.instance_variable_set :@frivol_hash, hash hash end def self.delete_hash(instance) key = instance.send(:storage_key) Frivol::Config.redis.del key instance.instance_variable_set :@frivol_hash, {} end end
  28. 28. Implementation – Instance Methods def store(keys_and_values) Frivol::Helpers.retrieve_hash self keys_and_values.each do |key, value| @frivol_hash[key.to_s] = value end Frivol::Helpers.store_hash self end def retrieve(keys_and_defaults) Frivol::Helpers.retrieve_hash self result = do |key, default| @frivol_hash[ key.to_s ] || ( default.is_a?(Symbol) && respond_to?(default) && => send(default) ) || default end return result.first if result.size == 1 result end def delete_storage Frivol::Helpers.delete_hash self end def expire_storage(time) return if time.nil? Frivol::Config.redis.expire storage_key, time end def storage_key @frivol_key ||= &quot;#{}-#{id}&quot; end
  29. 29. Problems <ul><li>Ruby 1.8 hash key order not guaranteed </li><ul><li>Problem destructuring assignment although that was the goal </li></ul><li>Single ”bucket” of storage </li><ul><li>All data for a class lumped together
  30. 30. Single expiry time </li></ul><li>Not thread safe </li><ul><li>Not a concern in goal use case </li></ul></ul>
  31. 31. Future Development <ul><li>Class methods for setting defaults
  32. 32. retrieve with a splat, instead of hash
  33. 33. Named storage buckets with own expiry </li><ul><li>Use method_missing to retrieve and store buckets
  34. 34. Or class methods to define buckets and defaults </li></ul><li>retrieve_hash method because Chris wants one
  35. 35. retrieve_default method to override class set default </li></ul>
  36. 36. Lessons Learnt <ul><li>You need good people to bounce your ideas off of and to pick apart your assumptions
  37. 37. You only really discover problems when you start using something in a real project </li><ul><li>When you write your first tests you will write them to test the way you expect your software to be used
  38. 38. Your first user will find a bug almost immediately </li></ul><li>Simple solutions are best and can often solve complex problems without becoming complex themselves
  39. 39. OpenOffice is pretty aweful for creating presentations (but it works) </li></ul>
  40. 40. Frivol - Frivolously simple temporary storage backed by Redis <ul><li>Github </li><ul><li> </li></ul><li>RubyGems </li><ul><li> </li></ul><li>Mentioned on Ruby5 </li><ul><li> </li></ul></ul>
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.