Project

cache-swr

0.0
The project is in a healthy, maintained state
Serve stale cached values while recomputing in the background to reduce tail latency.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 1.17
>= 13.0
~> 3.12
~> 0.22

Runtime

>= 4.0
 Project Readme

Cache SWR

Gem Version Gem Downloads Ruby CI GitHub Release Rails Elysium Arc

Server-side stale-while-revalidate caching for Rails.

About

Cache SWR stores a value plus two time windows: a fresh window and a stale window. Within the fresh window, values are returned immediately. Within the stale window, stale values are returned while a refresh runs in the background (or inline if you prefer).

This pattern reduces tail latency and keeps caches warm without blocking callers.

Use Cases

  • Reduce p99 latency for expensive reads with background refreshes
  • Serve dashboards and reports without blocking on cache refresh
  • Keep hot data warm while avoiding request pileups
  • Provide smoother cache behavior under load

Compatibility

  • Ruby 3.0+
  • ActiveSupport 6.1+
  • Works with ActiveSupport cache stores
  • Redis-backed stores are recommended when locking is enabled

Elysium Arc Reliability Toolkit

Also check out these related gems:

Installation

# Gemfile

gem "cache-swr"

Usage

value = Cache::SWR.fetch("expensive-key", ttl: 60, swr: 300, store: Rails.cache) do
  ExpensiveQuery.call
end

Rails integration adds Rails.cache.fetch_swr:

Rails.cache.fetch_swr("expensive-key", ttl: 60, swr: 300) { ExpensiveQuery.call }

If you are using an in-memory store, disable locking:

Cache::SWR.fetch("key", ttl: 30, swr: 120, store: ActiveSupport::Cache::MemoryStore.new, lock: false) do
  compute
end

Options

  • ttl (Integer) fresh window in seconds
  • swr (Integer) stale window in seconds
  • refresh (:async, :sync, or nil) refresh strategy
  • lock (Boolean) enable or disable locking
  • lock_ttl (Integer) lock expiry in seconds
  • lock_client Redis client for custom locking
  • store ActiveSupport cache store (defaults to Rails.cache when available)

Notes

  • During the SWR window, stale values are served while a refresh runs.
  • refresh: :async uses a background thread; choose :sync for deterministic refresh.
  • When lock is enabled, the store must expose redis or you must provide lock_client.

Release

bundle exec rake release