Redis.Cache (Redis v0.7.1)

Copy Markdown View Source

Client-side caching using RESP3 server-assisted invalidation.

Wraps a Redis.Connection and caches read command results locally. The Redis server tracks which keys this client has read and pushes invalidation messages when those keys are modified by any client.

How It Works

  1. On start, sends CLIENT TRACKING ON to enable server-assisted tracking
  2. Read commands (GET, MGET, HGETALL, etc.) check the local cache first
  3. Cache misses go to Redis — response is cached before returning
  4. When any client modifies a cached key, Redis pushes an invalidate message
  5. The push arrives as {:redis_push, :invalidate, keys} from Connection
  6. Cache evicts those keys locally
  7. Next read goes to Redis again

Usage

{:ok, cache} = Redis.Cache.start_link(port: 6379)

# First call: cache miss -> hits Redis
{:ok, "bar"} = Redis.Cache.get(cache, "foo")

# Second call: cache hit -> served locally
{:ok, "bar"} = Redis.Cache.get(cache, "foo")

# Another client does SET foo newval -> invalidation push -> evicted
# Next call: cache miss again
{:ok, "newval"} = Redis.Cache.get(cache, "foo")

# Generic cached command -- any allowlisted command works
{:ok, 3} = Redis.Cache.cached_command(cache, ["LLEN", "mylist"])
{:ok, ["a", "b"]} = Redis.Cache.cached_command(cache, ["LRANGE", "mylist", "0", "1"])

# Stats
Redis.Cache.stats(cache)
#=> %{hits: 1, misses: 2, evictions: 1, ...}

Options

  • All Redis.Connection options (host, port, password, etc.)
  • :ttl - local TTL in ms for cached entries (default: nil, rely on server invalidation)
  • :optin - if true, only cache commands prefixed with CACHING YES (default: false)
  • :max_entries - maximum number of cached entries (default: 10,000, 0 for unlimited)
  • :eviction_policy - :lru or :fifo (default: :lru)
  • :sweep_interval - ms between expired-entry sweeps (default: 60,000, nil to disable)
  • :cacheable - controls which commands are cached (default: :default). Accepts :default (built-in allowlist), a list of command entries (e.g. ["GET", {"LRANGE", ttl: 5_000}]), or a function ([String.t()] -> boolean | {:ok, ttl}).
  • :backend - module implementing Redis.Cache.Backend (default: Redis.Cache.Store)
  • :backend_opts - additional keyword list passed to backend.init/1
  • :name - GenServer name

Summary

Functions

Executes a command with caching if it is in the allowlist.

Returns a specification to start this module under a supervisor.

Sends a command through the underlying connection (not cached).

Flushes the local cache.

GET with caching. Returns {:ok, value} or {:ok, nil}.

HGETALL with caching.

MGET with caching.

Returns cache statistics.

Disables tracking and stops.

Functions

cached_command(cache, args)

@spec cached_command(GenServer.server(), [String.t()]) ::
  {:ok, term()} | {:error, term()}

Executes a command with caching if it is in the allowlist.

For allowlisted commands, results are cached locally and served from cache on subsequent calls with the same arguments. The cache key is derived from the full command arguments, and invalidation is tracked by the Redis key (first argument after the command name).

Non-allowlisted commands are passed through to Redis without caching.

{:ok, 3} = Redis.Cache.cached_command(cache, ["LLEN", "mylist"])
{:ok, ["a", "b"]} = Redis.Cache.cached_command(cache, ["LRANGE", "mylist", "0", "1"])

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

command(cache, args)

@spec command(GenServer.server(), [String.t()]) :: {:ok, term()} | {:error, term()}

Sends a command through the underlying connection (not cached).

flush(cache)

@spec flush(GenServer.server()) :: :ok

Flushes the local cache.

get(cache, key)

@spec get(GenServer.server(), String.t()) :: {:ok, term()} | {:error, term()}

GET with caching. Returns {:ok, value} or {:ok, nil}.

hgetall(cache, key)

@spec hgetall(GenServer.server(), String.t()) :: {:ok, term()} | {:error, term()}

HGETALL with caching.

mget(cache, keys)

@spec mget(GenServer.server(), [String.t()]) :: {:ok, [term()]} | {:error, term()}

MGET with caching.

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

stats(cache)

@spec stats(GenServer.server()) :: map()

Returns cache statistics.

stop(cache)

@spec stop(GenServer.server()) :: :ok

Disables tracking and stops.