Bonfire.Common.Cache (Bonfire v0.9.12-social-beta.71)

View Source

Helpers for caching data and operations.

This module provides functions to efficiently cache values and function results, with automatic expiration. Use it to avoid repeating expensive operations.

Summary

Functions

Converts function arguments to a string representation for cache keys.

Efficiently preloads and caches data for a list of objects.

Retrieves a value from the cache with the given key.

Retrieves a value from the cache with the given key and unwraps the result.

Generates a cache key for a function and its arguments.

Takes a function (or module and function names) and a set of arguments for that function, and tries to fetch the previous result of running that function from the in-memory cache, and if it's not in the cache it executes the function, and caches and returns the result.

Stores a value in the cache with the given key and options.

Removes the entry associated with a key from the cache.

Clears all entries from the cache.

Removes the result of a given function ran using maybe_apply_cached/3 from the cache.

Functions

args_to_string(args)

Converts function arguments to a string representation for cache keys.

For large argument lists, it creates a hash to keep keys at a reasonable length.

Examples

iex> Bonfire.Common.Cache.args_to_string(["hello"])
"\"hello\""

iex> Bonfire.Common.Cache.args_to_string("hello")
"\"hello\""

iex> Bonfire.Common.Cache.args_to_string([1, 2, 3, 4, 5])
"1, 2, 3, 4, 5"

iex> Bonfire.Common.Cache.args_to_string([0, [1, 2, 3, 4, 5]])
"0, [1, 2, 3, 4, 5]"

# For very long arguments, generates a hash
iex> Bonfire.Common.Cache.args_to_string(Enum.to_list(1..100))
"h:S-9J48qVhMunSA2R90s-Iw"
# Returns a hashed string

cached_preloads_for_objects(name, objects, fun, opts \\ [])

Efficiently preloads and caches data for a list of objects.

This function is useful when you need to fetch related data for a collection of objects (e.g. associations for a list of Ecto structs), and want to cache the results and minimize database queries.

Parameters

  • name - A name for this type of preload, used as part of the cache key
  • objects - List of objects that need preloading
  • fun - A function that takes a list of IDs and returns a map of {id, preloaded_data}

Examples

iex> users = [%{id: "01BX5ZZKBKACTAV9WEVGEMMVRZ", name: "Alice"}, %{id: "01BX5ZZKBKACTAV9WEVGEMMVS0", name: "Bob"}]
iex> loader = fn ids -> 
...>   # Simulating a database call that returns posts for users
...>   Enum.map(ids, fn id -> {id, ["Post by User"]} end) |> Map.new()
...> end
iex> Bonfire.Common.Cache.cached_preloads_for_objects("user_posts", users, loader)
%{"01BX5ZZKBKACTAV9WEVGEMMVRZ" => ["Post by User"], "01BX5ZZKBKACTAV9WEVGEMMVS0" => ["Post by User"]}

# On subsequent calls, data will be retrieved from cache

get(key, opts \\ [])

Retrieves a value from the cache with the given key.

Returns {:ok, value} if the key exists, {:ok, nil} if the key does not exist, or {:error, reason} if there was an error.

Options

  • :cache_store - The cache store to use (defaults to :bonfire_cache)

Examples

iex> Bonfire.Common.Cache.put("fetch_me", "hello")
iex> Bonfire.Common.Cache.get("fetch_me")
{:ok, "hello"}

iex> Bonfire.Common.Cache.get("non_existent_key")
{:ok, nil}

get!(key, opts \\ [])

Retrieves a value from the cache with the given key and unwraps the result.

Returns the value if the key exists or nil if it doesn't exist or there was an error.

Options

  • :cache_store - The cache store to use (defaults to :bonfire_cache)

Examples

iex> Bonfire.Common.Cache.put("my_key", "my_value")
iex> Bonfire.Common.Cache.get!("my_key")
"my_value"

iex> Bonfire.Common.Cache.get!("missing_key")
nil

key_for_call(fun, args)

Generates a cache key for a function and its arguments.

This function is used internally by maybe_apply_cached/3 to create consistent cache keys based on function references and their arguments.

Examples

iex> Bonfire.Common.Cache.key_for_call(fn x -> x * 2 end, [21])
iex> # Returns something like "fn/1 in Bonfire.Common.Cache.key_for_call/2(21)"
iex> # FYI actual result in doctest is more like "Bonfire.Common.CashTest."doctest Bonfire.Common.Cache.key_for_call/2 (13)"/1(21)"

iex> Bonfire.Common.Cache.key_for_call({String, :upcase}, "hello")
"String.upcase(\"hello\")"

iex> Bonfire.Common.Cache.key_for_call({String, :upcase}, ["hello"])
"String.upcase(\"hello\")"

iex> Bonfire.Common.Cache.key_for_call({Map, :get}, [%{"a"=>1, b: 2}, :a])
"Map.get([{:b, 2}, {\"a\", 1}], :a)"

maybe_apply_cached(fun, args \\ [], opts \\ [])

Takes a function (or module and function names) and a set of arguments for that function, and tries to fetch the previous result of running that function from the in-memory cache, and if it's not in the cache it executes the function, and caches and returns the result.

Uses the MFA (module name/function name/arguments used) to generate the cache key (see key_for_call/2 and args_to_string/1).

Options

  • :cache_store - The cache store to use (defaults to :bonfire_cache)
  • :cache_key - Custom cache key to use (defaults to auto-generated key based on function and args)
  • :expire - Time in milliseconds until the cache entry expires (defaults to 21600000ms)
  • :check_env - When set to false, bypasses error-retry logic in dev environment (defaults to true)

Examples

iex> Bonfire.Common.Cache.maybe_apply_cached({String, :upcase}, ["hello"])
"HELLO"

iex> # Second call uses cached result
iex> Bonfire.Common.Cache.maybe_apply_cached({String, :upcase}, ["hello"])
"HELLO"

iex> Bonfire.Common.Cache.maybe_apply_cached(fn x -> x * 2 end, [21])
42

put(key, value, opts \\ [])

Stores a value in the cache with the given key and options.

Options

  • :cache_store - The cache store to use (defaults to :bonfire_cache)
  • :expire - Time in milliseconds until the cache entry expires (defaults to 21600000ms / 6 hours)

Examples

iex> Bonfire.Common.Cache.put("my_key", "my_value")
"my_value"
iex> Bonfire.Common.Cache.get("my_key")
{:ok, "my_value"}

iex> Bonfire.Common.Cache.put("expires_soon", "temporary", expire: 1000)
"temporary"

remove(key, opts \\ [])

Removes the entry associated with a key from the cache.

Options

  • :cache_store - The cache store to use (defaults to default_cache_store/0})

Examples

iex> Bonfire.Common.Cache.put("delete_me", "value")
iex> Bonfire.Common.Cache.remove("delete_me")
true
iex> Bonfire.Common.Cache.get!("delete_me")
nil

remove_all(opts \\ [])

Clears all entries from the cache.

Options

  • :cache_store - The cache store to use (defaults to :bonfire_cache)

Examples

iex> Bonfire.Common.Cache.remove_all()
iex> Bonfire.Common.Cache.put("key1", "value1")
iex> Bonfire.Common.Cache.put("key2", "value2")
iex> Bonfire.Common.Cache.remove_all()
2 # Returns the number of entries removed
iex> Bonfire.Common.Cache.get!("key1")
nil

reset(fun, args, opts \\ [])

Removes the result of a given function ran using maybe_apply_cached/3 from the cache.

This is useful when you know a cached value is stale and want to force re-computation on the next call.

Options

  • :cache_store - The cache store to use (defaults to default_cache_store/0})

Examples

iex> Bonfire.Common.Cache.maybe_apply_cached({String, :upcase}, ["hello"])
"HELLO"
iex> Bonfire.Common.Cache.reset({String, :upcase}, ["hello"])
true
iex> # Will compute the result again
iex> Bonfire.Common.Cache.maybe_apply_cached({String, :upcase}, ["hello"])
"HELLO"