AshCache keeps cached results in a store. This guide covers the stores that ship with the package, how to give a resource its own store, and how to write an adapter for other storage.
Built-in adapters
| Adapter | What it does | Use it for |
|---|---|---|
AshCache.Store.Adapters.Cachex | Keeps entries in memory with Cachex. This is the default. Add {:cachex, "~> 3.6"} to your deps to use it. | Production on one server |
AshCache.Store.Adapters.Nebulex | Keeps entries in your own Nebulex cache. | Several servers (experimental) |
AshCache.Store.Adapters.ProcessLocal | Gives each process its own private cache. | Tests |
AshCache.Store.Adapters.Noop | Saves nothing. Every read goes to the database. | Turning caching off |
Choose one for the whole application in config:
config :ash_cache, adapter: AshCache.Store.Adapters.NoopOr for the current process only:
Process.put(:ash_cache_adapter, AshCache.Store.Adapters.Noop)Running on several servers (experimental)
Experimental
Multi-server support was written with AI help and has not been tried on real servers. Its tests run three Elixir nodes on one computer. Don't rely on it in production until you have tested it in your own setup, and please report what you find.
The default Cachex store keeps each server's cache in that server's memory.
On several servers, a write clears the cache only on the server that made
it, and the others serve old results until ttl runs out.
The AshCache.Store.Adapters.Nebulex adapter is meant to share one cache
between servers through a Nebulex cache that
you set up yourself:
- Add
{:nebulex, "~> 3.1"}and a Nebulex adapter to your deps. - Define a Nebulex cache module, for example
MyApp.Cache, and start it in your supervision tree instead ofAshCache.Supervisor. - Set
config :ash_cache, adapter: AshCache.Store.Adapters.Nebulex. - Set
store MyApp.Cachein thecacheblock of every cached resource.
Give a resource its own store
All resources share the :ash_cache store by default. Set store to give
a resource a store of its own:
cache do
store :products_cache
read :read, ttl: :timer.minutes(10)
endWith the default Cachex adapter, AshCache.Supervisor starts every store
your resources name. To empty one
store without touching the others:
AshCache.clear_store(:products_cache)Write your own adapter
An adapter is a module that implements AshCache.Store.Adapter: get/2,
put/4, delete/2 and clear/1. Start from the built-in
Cachex adapter,
which is about thirty lines.
Your adapter has to follow these rules:
- Keys are Elixir terms, not strings. They contain tuples, maps and structs. A store such as Redis needs them turned into strings first.
- A missing key returns
{:ok, nil}, not an error. put/4gets a:ttlin milliseconds, or:infinity.put/4can getnever_evict: true. Keep that entry when making room if you can. AshCache uses it for the version values that make clearing work. Losing one is safe but makes every cached read of that resource miss once.clear/1removes only the given store's entries, not everything in the backend.
Set it as the adapter:
config :ash_cache, adapter: MyApp.MyCacheAdapterPass options to your adapter
Anything a read sets in store_options is passed to your put/4
along with :ttl:
cache do
read :read, ttl: :timer.minutes(10), store_options: [prefix: "products"]
endTest your adapter
Copy the package's contract test, test/support/store_contract.ex in the
repository. It runs the same get, put, delete, clear and expiry checks
against every built-in adapter.