Class: Startback::Caching::EntityCache

Inherits:
Object
  • Object
show all
Defined in:
lib/startback/caching/entity_cache.rb

Overview

A overriable caching abstraction aiming at making Entity-based caching easy.

This class MUST be overriden:

  • the ‘load_entity` protected method MUST be implemented to load data from a primary & context unaware key.

  • the ‘primary_key` protected method MAY be implemented to convert candidate keys (received from ultimate callers) to primary keys. The method is also a good place to check and/or log the keys actually used by callers.

  • the ‘context_free_key` protected method MAY be overriden to provide domain unrelated caching keys from primary keys, e.g. by encoding the context into the caching key itself, if needed.

  • the ‘valid?` protected method MAY be overriden to check validity of data extracted from the cache and force a refresh even if found.

An EntityCache takes an actual store at construction. The object must meet the specification writtern in Store. The ‘cache’ ruby gem can be used in practice.

This class supports listeners to track cache hits, misses, outdates and failures. Listeners can be provided at construction via the options, or by overriding the ‘default_listeners` method. The default implementation simply logs.

By default, this class raises an error if something goes wrong with the cache. You can disable this by using the ‘raise_on_cache_fail` option.

Constant Summary collapse

DEFAULT_OPTIONS =

class DSL

{

  # Whether a cache fail raises an exception or not
  raise_on_cache_fail: true,

  # Default listeners to use, if any. When nil is used, `default_listener`
  # method is used to create them.
  listeners: nil,

}

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(store, context = nil, options = {}) ⇒ EntityCache

Returns a new instance of EntityCache.



61
62
63
64
65
66
# File 'lib/startback/caching/entity_cache.rb', line 61

def initialize(store, context = nil, options = {})
  @store = store
  @context = context
  @options = DEFAULT_OPTIONS.merge(options)
  @options[:listeners] ||= default_listeners
end

Class Attribute Details

.default_ttlObject



44
45
46
# File 'lib/startback/caching/entity_cache.rb', line 44

def default_ttl
  @default_ttl || (superclass.respond_to?(:default_ttl, true) && superclass.default_ttl) || 3600
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



67
68
69
# File 'lib/startback/caching/entity_cache.rb', line 67

def context
  @context
end

#storeObject (readonly)

Returns the value of attribute store.



67
68
69
# File 'lib/startback/caching/entity_cache.rb', line 67

def store
  @store
end

Instance Method Details

#get(candidate_key, caching_options = default_caching_options) ⇒ Object

Returns the entity corresponding to a given key.

If the entity is not in cache, loads it and puts it in cache using the caching options passed as second parameter.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/startback/caching/entity_cache.rb', line 73

def get(candidate_key, caching_options = default_caching_options)
  pkey = primary_key(candidate_key)
  cache_key = encode_key(context_free_key(pkey))
  if store.exist?(cache_key)
    cached = store.get(cache_key)
    if valid?(pkey, cached)
      cache_hit(pkey, cached)
      return cached
    else
      cache_outdated(pkey, cached)
    end
  end
  cache_miss(pkey)
  load_entity(pkey).tap{|to_cache|
    store.set(cache_key, to_cache, caching_options)
  }
rescue => ex
  raise if raise_on_cache_fail? || pkey.nil?
  cache_fail(pkey, ex)
  load_entity(pkey)
end

#invalidate(candidate_key) ⇒ Object

Invalidates the cache under a given key.



96
97
98
99
100
# File 'lib/startback/caching/entity_cache.rb', line 96

def invalidate(candidate_key)
  pkey = primary_key(candidate_key)
  cache_key = encode_key(context_free_key(pkey))
  store.delete(cache_key)
end