A Cachex-based, local or distributed, in-memory cache adapter for Lotus.
This adapter requires the Cachex library. Please add {:cachex, "~> 4.0"} to your dependencies.
Example configuration in config/runtime.exs:
config :lotus, :cache,
adapter: Lotus.Cache.Cachex,
cachex_opts: [limit: 1_000_000] # Optional Cachex optionsSee Cachex documentation for available options.
Routing
Without cachex_opts, the value cache starts with
Cachex.Router.Ring and monitor: true: entries are spread over the
connected nodes by key, nodes that join or leave are picked up, and one
node's result serves the whole cluster. Any cachex_opts you pass
replace that default entirely, so a host that sets limit: alone gets
Cachex's own default, Cachex.Router.Local. Add the router back to keep
distributed mode:
cachex_opts: [
limit: 1_000_000,
router: Cachex.Spec.router(module: Cachex.Router.Ring, options: [monitor: true])
]Choose a router by following the Cachex docs.
Tags and invalidation in a cluster
Cachex routes one key per call and rejects a transaction whose keys live
on different nodes, and a function passed to a routed call runs on the
node that owns the key. This adapter therefore keeps its tag bookkeeping
on the node that wrote the entry, in a second cache that always uses
Cachex.Router.Local, and invalidate_tags/1 deletes each key with its
own routed call. Because that bookkeeping is per node,
scope(:invalidate_tags) is :node and Lotus.Cache relays every
invalidate_tags/1 to the other nodes over Lotus.Notifier, where each
node drops the keys it tagged. A single-key delete/1 is routed by
Cachex to the node that owns the key, so scope(:delete) is :cluster
and it is not relayed. get_or_store/4 runs the fetch function on the
caller's node and writes the result with a routed put/4.
A tag's record holds each key with the expiry of the entry it points at. Expired keys are pruned from the record at most every 30 seconds on write, and the record itself expires with the longest-lived entry it holds, so a tag that is never invalidated does not grow for the life of the node.