class Hoodoo::TransientStore
A simple abstraction over transient storage engines such as Memcached or Redis, making it it easier for client code to switch engines with very few changes. If the storage engine chosen when creating instances of this object is defined in application-wide configuration data, all you would need to do is change the configuration for all new TransientStore
instances to use the new engine.
Attributes
Read this instance’s default item maximum lifespan, in seconds. See also ::new
.
Read this instance’s default storage namespace, as a String. See also ::new
.
Read this instance’s storage engine; see ::supported_storage_engines
and ::new
.
Read the storage engine instance for the storage_engine
- this allows engine-specific configuration to be set where available, though this is strongly discouraged as it couples client code to the engine in use, defeating the main rationale behind the TransientStore
abstraction.
Public Class Methods
Remove a storage engine plugin class from the supported collection. Any existing Hoodoo::TransientStore
instances using the removed class will not be affected, but new instances cannot be made.
Named parameters are:
as
-
The value given to register in the corresponding
as
parameter.
# File lib/hoodoo/transient_store/transient_store.rb, line 69 def self.deregister( as: ) @@supported_storage_engines.delete( as ) end
Instantiate a new Transient storage object through which temporary data can be stored or retrieved.
The TransientStore
abstraction is a high level and simple abstraction over heterogenous data storage engines. It does not expose the many subtle configuration settings usually available in such. If you need to take advantage of those at an item storage level, you’ll need to use a lower level interface and thus lock your code to the engine of choice.
Engine plug-ins are recommended to attempt to gain and test a connection to the storage engine when this object is constructed, so if building a TransientStore
instance, ensure your chosen storage engine is running first. Exceptions may be raised by storage engines, so you will probably want to catch those with more civilised error handling code.
Named parameters are:
storage_engine
-
An entry from
::supported_storage_engines
. storage_host_uri
-
The engine-dependent connection URI. Consult documentation for your chosen engine to find out its connection URI requirements, along with the documentation for the constructor method of the plug-in in use, since in some cases requirements may be unusual (e.g. in
Hoodoo::TransientStore::MemcachedRedisMirror
). default_maximum_lifespan
-
The default time-to-live for data items, in, seconds; can be overridden per item; default is 604800 seconds or 7 days.
default_namespace
-
Storage engine keys are namespaced with
nz_co_loyalty_hoodoo_transient_store_
by default, though this can be overridden here. Pass a String or Symbol.
# File lib/hoodoo/transient_store/transient_store.rb, line 143 def initialize( storage_engine:, storage_host_uri:, default_maximum_lifespan: 604800, default_namespace: 'nz_co_loyalty_hoodoo_transient_store_' ) unless self.class.supported_storage_engines().include?( storage_engine ) # Be kind and use 'inspect' to indicate that we expect Symbols here # in the exception, because of the arising leading ':' in the output. # engines = self.class.supported_storage_engines().map { | symbol | "'#{ symbol.inspect }'" } allowed = engines.join( ', ' ) raise "Hoodoo::TransientStore: Unrecognised storage engine '#{ storage_engine.inspect }' requested; allowed values: #{ allowed }" end @default_maximum_lifespan = default_maximum_lifespan @default_namespace = ( default_namespace || '' ).to_s() @storage_engine = storage_engine @storage_engine_instance = @@supported_storage_engines[ storage_engine ].new( storage_host_uri: storage_host_uri, namespace: @default_namespace ) end
Register a new storage engine plugin class. It MUST inherit from and thus follow the template laid out in Hoodoo::TransientStore::Base
.
Named parameters are:
as
-
The name, as a Symbol, for the
::new
storage_engine
input parameter, to select this plugin. using
-
The class reference of the
Hoodoo::TransientStore::Base
subclass to be associated with the name given inas
.
Example:
Hoodoo::TransientStore.register( as: :memcached, using: Hoodoo::TransientStore::Memcached )
# File lib/hoodoo/transient_store/transient_store.rb, line 45 def self.register( as:, using: ) as = as.to_sym @@supported_storage_engines = {} unless defined?( @@supported_storage_engines ) unless using < Hoodoo::TransientStore::Base raise "Hoodoo::TransientStore.register requires a Hoodoo::TransientStore::Base subclass - got '#{ using.to_s }'" end if @@supported_storage_engines.has_key?( as ) raise "Hoodoo::TransientStore.register: A storage engine called '#{ as }' is already registered" end @@supported_storage_engines[ as ] = using end
Return an array of the names of all supported storage engine names known to the Hoodoo::TransientStore
class. Any one of those names can be used with the ::new
storage_engine
parameter.
# File lib/hoodoo/transient_store/transient_store.rb, line 77 def self.supported_storage_engines @@supported_storage_engines.keys() end
Public Instance Methods
If you aren’t going to use this instance again, it is good manners to immediately close its connection(s) to any storage engines by calling here.
No useful return value is generated and exceptions are ignored.
# File lib/hoodoo/transient_store/transient_store.rb, line 323 def close @storage_engine_instance.close() rescue nil end
Delete data previously stored with set
.
Named parameters are:
key
-
Key previously given to
set
.
Returns:
-
true
if deletion was successful, if the item has already expired or if the key is simply not recognised so there is no more work to do. -
false
if deletion failed but the reason is unknown. -
An
Exception
instance if deletion failed and the storage engine raised an exception describing the problem.
Only non-empty String or Symbol keys are permitted, else an exception will be raised.
# File lib/hoodoo/transient_store/transient_store.rb, line 299 def delete( key: ) key = normalise_key( key, 'delete' ) begin result = @storage_engine_instance.delete( key: key ) if result != true && result != false raise "Hoodoo::TransientStore\#delete: Engine '#{ @storage_engine }' returned an invalid response" end rescue => e result = e end return result end
Retrieve data previously stored with set
.
Named parameters are:
key
-
Key previously given to
set
. allow_throw
-
If
true
, exceptions raised by the underlying storage engine are thrown, else ignored andnil
is returned. Optional; default isfalse
.
Returns nil
if the item is not found - either the key is wrong, the stored data has expired or the stored data has been evicted early from the storage engine’s pool.
Only non-empty String or Symbol keys are permitted, else an exception will be raised.
# File lib/hoodoo/transient_store/transient_store.rb, line 272 def get( key:, allow_throw: false ) key = normalise_key( key, 'get' ) begin @storage_engine_instance.get( key: key ) rescue raise if allow_throw end end
Set (write) a given payload into the storage engine with the given payload and maximum lifespan.
Payloads must only contain simple types such as Hash, Array, String and Integer. Complex types like Symbol, Date, Float, BigDecimal or custom objects are unlikely to serialise properly but since this depends upon the storage engine in use, errors may or may not be raised for misuse.
Storage engines usually have a maximum payload size limit; consult your engine administrator for information. For example, the default - but reconfigurable - maximum payload size for Memcached
is 1MB.
For maximum possible compatibility:
-
Use only Hash payloads with String key/value paids and no nesting. You may choose to marshal the data into a String manually for unusual data requirements, manually converting back when reading stored data.
-
Keep the payload size as small as possible - large objects belong in bulk storage engines such as Amazon S3.
These are only guidelines though - heterogenous storage engine support and the ability of system administrators to arbitrarily configure those storage engines makes it impossible to be more precise.
Returns:
-
true
if storage was successful -
false
if storage failed but the reason is unknown -
An
Exception
instance if storage failed and the storage engine raised an exception describing the problem.
Named parameters are:
key
-
Storage key to use in the engine, which is then used in subsequent calls to
get
and possibly eventually todelete
. Only non-empty Strings or Symbols are permitted, else an exception will be raised. payload
-
Payload data to store under the given
key
. A flat Hash is recommended rather than simple types such as String (unless marshalling a complex type into such) in order to make potential additions to stored data easier to implement. Note thatnil
is prohibited. maximum_lifespan
-
Optional maximum lifespan, seconds. Storage engines may chooset to evict payloads sooner than this; it is a maximum time, not a guarantee. Omit to use this
TransientStore
instance’s default value - see::new
. If you know you no longer need a piece of data at a particular point in the execution flow of your code, explicitly delete it viadelete
rather than leaving it to expire. This maximises the storage engine’s pool free space and so minimises the chance of early item eviction.
# File lib/hoodoo/transient_store/transient_store.rb, line 227 def set( key:, payload:, maximum_lifespan: nil ) key = normalise_key( key, 'set' ) if payload.nil? raise "Hoodoo::TransientStore\#set: Payloads of 'nil' are prohibited" end maximum_lifespan ||= @default_maximum_lifespan begin result = @storage_engine_instance.set( key: key, payload: payload, maximum_lifespan: maximum_lifespan ) if result != true && result != false raise "Hoodoo::TransientStore\#set: Engine '#{ @storage_engine }' returned an invalid response" end rescue => e result = e end return result end