Generic caching system for PhoenixKit with ETS-backed storage.
This module provides a flexible caching foundation that can be used for:
- Settings caching
- User roles and permissions
- Module configurations
- Any frequently accessed data
Features
- ETS-backed storage for high-performance lookups
- Automatic cache warming
- TTL support for expiring data
- Statistics tracking
- Robust fallback mechanisms
- Multiple cache instances via registry
Usage
# Start a cache instance
{:ok, pid} = PhoenixKit.Cache.start_link(name: :my_cache, warmer: &MyApp.load_data/0)
# Basic operations
PhoenixKit.Cache.put(:my_cache, "key", "value")
PhoenixKit.Cache.get(:my_cache, "key", "default")
PhoenixKit.Cache.invalidate(:my_cache, "key")
# Batch operations
PhoenixKit.Cache.get_multiple(:my_cache, ["key1", "key2"], %{"key1" => "default1"})
PhoenixKit.Cache.invalidate_multiple(:my_cache, ["key1", "key2"])Configuration
Cache instances can be configured with:
:name- Unique name for the cache instance:warmer- Function to warm the cache on startup:ttl- Time-to-live for cache entries (optional):max_size- Maximum number of entries (optional)
Summary
Functions
Returns a specification to start this module under a supervisor.
Clears all entries from the cache.
Clears all cache entries whose keys start with the given prefix.
Gets a value from the cache.
Gets multiple values from the cache.
get_multiple/3, plus the generation — see get_with_generation/3.
Invalidates a key in the cache.
Invalidates multiple keys in the cache.
Invalidates keys and returns only once they are gone.
Puts a value in the cache.
Puts multiple values in the cache. Takes if_generation: like put/4.
Starts a new cache instance.
Gets cache statistics.
Warms the cache using the configured warmer function.
Types
@type cache_key() :: any()
@type cache_name() :: atom()
@type cache_value() :: any()
@type default_value() :: any()
@type options() :: [ name: cache_name(), warmer: warmer_fun(), ttl: pos_integer() | nil, max_size: pos_integer() | nil ]
@type warmer_fun() :: (-> map() | nil)
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec clear(cache_name()) :: :ok
Clears all entries from the cache.
Examples
PhoenixKit.Cache.clear(:settings)
@spec clear_by_prefix(cache_name(), String.t()) :: {:ok, non_neg_integer()} | {:error, any()}
Clears all cache entries whose keys start with the given prefix.
Returns the count of entries cleared.
Examples
PhoenixKit.Cache.clear_by_prefix(:publishing_posts, "v1:publishing_post:my-blog:")
# => {:ok, 15}
@spec get(cache_name(), cache_key(), default_value()) :: cache_value()
Gets a value from the cache.
Returns the default value if the key is not found or the cache is unavailable.
Examples
PhoenixKit.Cache.get(:settings, "date_format", "Y-m-d")
PhoenixKit.Cache.get(:user_roles, user_uuid, [])
@spec get_multiple(cache_name(), [cache_key()], map()) :: map()
Gets multiple values from the cache.
Returns a map with the requested keys and their values, using defaults for missing keys.
Examples
defaults = %{"date_format" => "Y-m-d", "time_format" => "H:i"}
PhoenixKit.Cache.get_multiple(:settings, ["date_format", "time_format"], defaults)
@spec get_multiple_with_generation(cache_name(), [cache_key()], map()) :: {map(), non_neg_integer() | nil}
get_multiple/3, plus the generation — see get_with_generation/3.
@spec get_with_generation(cache_name(), cache_key(), default_value()) :: {cache_value(), non_neg_integer() | nil}
get/3, plus the cache's generation at the moment of the read — for a
caller that fills a miss from the database. Pass it to put/4 as
if_generation:.
A miss-fill races every write: the reader misses, reads the old row, and
the writer commits and invalidates before the reader's put arrives. That
put would bring the old value back after the invalidation, and it would
stay until its TTL. Carrying the generation drops it instead.
The generation is nil when the cache could not answer; a put/4 with
if_generation: nil writes nothing.
@spec invalidate(cache_name(), cache_key()) :: :ok
Invalidates a key in the cache.
Examples
PhoenixKit.Cache.invalidate(:settings, "date_format")
@spec invalidate_multiple(cache_name(), [cache_key()]) :: :ok
Invalidates multiple keys in the cache.
Examples
PhoenixKit.Cache.invalidate_multiple(:settings, ["date_format", "time_format"])
@spec invalidate_now(cache_name(), [cache_key()]) :: :ok
Invalidates keys and returns only once they are gone.
invalidate/2 and invalidate_multiple/2 are casts: the caller moves on
while the cache process still holds the old values. That is fine for a
write nobody is watching, and wrong for one that is about to be announced —
a subscriber that reacts to "this setting changed" by reading it again
would get the value from before the change. Use this when a notification
follows.
Never turns a successful write into a failure: a slow, dead or missing
cache process is logged and reported as :ok, and the entry expires on its
TTL like any other.
@spec put(cache_name(), cache_key(), cache_value(), keyword()) :: :ok
Puts a value in the cache.
With if_generation: generation (from get_with_generation/3), the value
is written only if nothing has been invalidated since that read — the form
a miss-fill must use. Without it the write is unconditional.
Examples
PhoenixKit.Cache.put(:settings, "date_format", "m/d/Y")
PhoenixKit.Cache.put(:user_roles, user_uuid, ["admin", "user"])
@spec put_multiple(cache_name(), map(), keyword()) :: :ok
Puts multiple values in the cache. Takes if_generation: like put/4.
Examples
PhoenixKit.Cache.put_multiple(:settings, %{"date_format" => "m/d/Y", "time_format" => "h:i A"})
@spec start_link(options()) :: GenServer.on_start()
Starts a new cache instance.
Options
:name- Required. Unique name for the cache instance:warmer- Optional. Function to warm the cache on startup:ttl- Optional. Time-to-live for cache entries in milliseconds:max_size- Optional. Maximum number of entries before eviction
Examples
{:ok, pid} = PhoenixKit.Cache.start_link(name: :settings)
{:ok, pid} = PhoenixKit.Cache.start_link(name: :user_roles, warmer: &MyApp.load_user_roles/0)
@spec stats(cache_name()) :: map()
Gets cache statistics.
Examples
PhoenixKit.Cache.stats(:settings)
# => %{hits: 150, misses: 5, puts: 20, invalidations: 3, hit_rate: 0.97}
@spec warm(cache_name()) :: :ok
Warms the cache using the configured warmer function.
Examples
PhoenixKit.Cache.warm(:settings)