Module: Cacheable

Defined in:
lib/cacheable.rb,
lib/cache_utils.rb,
lib/cache_configuration.rb

Defined Under Namespace

Classes: CacheConfiguration, TestCache, TestLogger, Utils

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.cacheObject



5
6
7
# File 'lib/cache_configuration.rb', line 5

def self.cache
  CacheConfiguration.cache
end

.included(base) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/cacheable.rb', line 5

def self.included(base)
  base.class_eval do

    def self.method_missing(name, *args, &block)
      query_attributes = []

      if name.to_s.start_with? 'fetch_by_'
        # puts("\n\nname = #{name}\nname['fetch_by_'.length, name.length] = #{name['fetch_by_'.length, name.length]}")

        query_attributes = name['fetch_by_'.length, name.length].split('_and_')
        return nil if query_attributes == []

        # puts("\n\n Cacheable method_missing - query attributes = #{query_attributes}, arguments = #{args.inspect}\n\n")

        find_in_cache(query_attributes,args) or refresh_cache(query_attributes, args)
      else
        super
      end

    end

    # Use this method if you want to explicitly re-fetch the whole object with given attributes-values, and write the newly fetched object to the cache
    def self.refresh_cache(attributes, args)

      obj = fetch(attributes, args)
      return nil if obj.nil?

      obj.cached_by_attributes = attributes
      return obj.update_cache

      rescue => error
        Cacheable::logger.error("\n\nError in Cacheable.refresh_cache error = #{error.message}\n#{error.backtrace.join("\n")}\n\n")
        return nil
    end

    # This method must be implemented by subclasses, because only subclasses know how to do the actual data fetch
    def self.fetch(attributes,args)
      raise 'The method <fetch> must be implemented by subclass'
    end

    # including classes that want to have time-based expire can implement this method
    # can be 5.minutes, 1.day ...etc...
    # 0 is never expire
    def self.cache_expired_duration
      600 # default to 10 minutes
    end

    private
    def self.find_in_cache(attributes,args)
      cache_key = build_cache_key(attributes,args)

      obj = Cacheable::cache.fetch(cache_key)
      if cache_expired_duration > 0
        cached_time = Cacheable::cache.fetch(build_cached_time_key(attributes,args)) || 0
        return refresh_cache(attributes, args) if ( (Time.now.to_i - cached_time > cache_expired_duration) && obj)
      end

      obj
    end

    def self.save_to_cache(attributes, args, obj)
      cache_key = build_cache_key(attributes,args)
      options = {}

      if cache_expired_duration > 0
        options = { expires_in: cache_expired_duration.to_i }
        Cacheable::cache.write(build_cached_time_key(attributes,args), Time.now.to_i)
      end

      Cacheable::cache.write(cache_key, obj, options)
    end

    def self.build_cache_key(attributes,args)
      "#{self.name}_#{attributes.join('_')}_#{args.map(&:to_s).join('_')}"
    end

    # store the time when the object is cached
    def self.build_cached_time_key(attributes,args)
      "#{build_cache_key(attributes,args)}_cached_time"
    end

  end
end

.loggerObject



9
10
11
# File 'lib/cache_configuration.rb', line 9

def self.logger
  CacheConfiguration.logger
end

Instance Method Details

#cached_by_attributes=(attributes) ⇒ Object

All the attributes that instances of classes are cached by are dynamically created and store in cache in order to support multiple runtimes of cache server



125
126
127
128
129
130
131
132
133
# File 'lib/cacheable.rb', line 125

def cached_by_attributes=(attributes)
  all_attributes = all_cached_by_attributes
  cached_attributes_for_class = all_attributes[self.class.name] || []

  cached_attributes_for_class << attributes if !cached_attributes_for_class.include?(attributes)

  all_attributes[self.class.name] = cached_attributes_for_class
  Cacheable::cache.write('all_cached_by_attributes', all_attributes)
end

#delete_from_cacheObject

Delete cached object from cache For example if you have a cached current_profile, and you want to delete it out of cache use current_profile.delete_from_cache



93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/cacheable.rb', line 93

def delete_from_cache
  cached_key_attributes = cached_by_attributes
  raise "This object has never been cached in the cache #{self.inspect}" if cached_key_attributes.nil?

  cached_key_attributes.each do |attribute_keys|
    attribute_values = build_attribute_values(attribute_keys)
    cache_key = self.class.build_cache_key(attribute_keys,attribute_values)
    Cacheable::cache.delete(cache_key)
  end

  self
end

#update_cacheObject

This method updates all instances of an object with all cached keys (cached by different attributes) If you have an instance of a cached object, you just modify it or partially modify it, and want to write it back to the cache then use this method. For example if you have a current_profile, and its info changed, use current_profile.update_cache



109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/cacheable.rb', line 109

def update_cache
  cached_key_attributes = cached_by_attributes
  raise "This object has never been cached in the cache #{self.inspect}" if cached_key_attributes.nil?

  cached_key_attributes.each do |attribute_keys|
    attribute_values = build_attribute_values(attribute_keys)
    self.class.save_to_cache(attribute_keys, attribute_values, self)
  end

  self

end