Lighthouse ticket: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/4452
I have recently been working on some gems that utilize
ActiveSupport::Cache and ran into some issues with the different
implementations handling the same functionality differently. One of
the issues was that I couldn't rely on expiring entries with
the :expires_in option. MemCacheStore takes this option on a write,
while FileStore takes it on a read, and MemoryStore ignores it all
together so that the cache will just grow until you run out of memory.
I ended up doing a pretty large refactoring of ActiveSupport::Cache to
provide universal support for some options, fix some bugs, and update
the documentation. The patch is attached to this ticket.
Here are the highlights:
* Add default options to initializer that will be sent to all
read, write, fetch, exist?, increment, and decrement
* Add support for the :expires_in option to fetch and write for
all caches. Cache entries are stored with the create timestamp and a
ttl so that expiration can be handled independently of the
* Add support for a :namespace option. This can be used to set a
global prefix for cache entries.
* Deprecate expand_cache_key on ActiveSupport::Cache and move it
to ActionController::Caching and ActionDispatch::Http::Cache since the
logic in the method used some Rails specific environment variables and
was only used by ActionPack classes. Not very DRY but there didn't
seem to be a good shared spot and ActiveSupport really shouldn't be
* Add support for :race_condition_ttl to fetch. This setting can
prevent race conditions on fetch calls where several processes try to
regenerate a recently expired entry at once.
* Add support for :compress option to fetch and write which will
compress any data over a configurable threshold.
* Nil values can now be stored in the cache and are distinct from
cache misses for fetch.
* Easier API to create new implementations. Just need to implement
the methods read_entry, write_entry, and delete_entry instead of
overwriting existing methods.
* Since all cache implementations support storing objects, update
the docs to state that ActiveCache::Cache::Store implementations
should store objects. Keys, however, must be strings since some
implementations require that.
* Increase test coverage.
* Document methods which are provided as convenience but which may
not be universally available.
* MemoryStore can now safely be used as the cache for single
* Make thread safe so that the default cache implementation used
by Rails is thread safe. The overhead is minimal and it is still the
fastest store available.
* Provide :size initialization option indicating the maximum size
of the cache in memory (defaults to 32Mb).
* Add prune logic that removes the least recently used cache
entries to keep the cache size from exceeding the max.
* Deprecated SynchronizedMemoryStore since it isn't needed
* Escape key values so they will work as file names on all file
systems, be consistent, and case sensitive
* Use a hash algorithm to segment the cache into sub directories
so that a large cache doesn't exceed file system limits.
* FileStore can be slow so implement the LocalCache strategy to
cache reads for the duration of a request.
* Add cleanup method to keep the disk from filling up with expired
* Fix increment and decrement to use file system locks so they are
consistent between processes.
* Support all keys. Previously keys with spaces in them would fail
* Deprecate CompressedMemCacheStore since it isn't needed anymore