The decision cache: {epoch, method, segments} → matched route id, or the
reason no route matched.
Pattern routes can't be found by one key lookup, so the guard would otherwise scan the compiled pattern list on every request. Caching the decision turns the common case — the same provider POSTing to the same path over and over — into one ETS read.
Only matching is cached
IP decisions are not cached: they are per-client-address, and the rule list is a short in-memory scan of bitmasks. Caching them would mean a key space proportional to the number of distinct senders, for a saving smaller than the cache lookup itself.
Epoch-keyed, plus a TTL
The key carries the snapshot's epoch: a number Ankusa.Routes.Snapshot
draws afresh for every snapshot it publishes and never reuses. Publishing a
snapshot therefore makes every earlier entry unreachable at once — no delete
pass, no invalidation broadcast.
The epoch, not the store's version, is the key because versions are
reused: an in-memory store that restarts starts over at 1, and a Redis that is
flushed starts its counter again, and either would let an entry cached against
the old table answer for the new one. Stale entries age out on their own TTL
and are collected by the adapter's generational sweep; nothing depends on them
expiring, so the TTL only has to bound memory.
A cached rejection uses a shorter TTL than a cached match: a rejection is what a scanner hitting random paths produces, and there are far more of those than there are real routes.
Bounded keys
The key holds the request's own path, which the sender chooses. Only requests
of at most 16 segments and 256 bytes of path are cached
(see cacheable?/1); anything longer is matched by a scan and never stored, so
a scanner sending long random paths can't fill the cache with large keys.
Why Nebulex
nebulex_local is a generation-based ETS cache with max_size; the
alternative was hand-rolling eviction, TTL expiry, and a sweep timer for the
same thing. It enforces max_size in a periodic memory check
(gc_memory_check_interval, one second here) rather than on every write, so
the size is approximate between checks — and an evicted entry only costs a
re-scan, never a wrong decision. Core carries the dependency because every
deployment that turns routes on wants it — the Redis store is the part that
stays in an adapter package, since only multi-node deployments need it.
Instance-scoped: the cache process registers under
Ankusa.via(instance, :routes_cache), and the Nebulex API is addressed with
that process's pid (Nebulex resolves a cache by atom or pid, and a
Registry-based name is neither).
Summary
Functions
Is this request path short enough to be a cache key? The limits are on the segment count and the summed segment bytes, walked without allocating.
Callback implementation for Nebulex.Cache.count_all/2.
Callback implementation for Nebulex.Cache.count_all/3.
Callback implementation for Nebulex.Cache.count_all!/2.
Callback implementation for Nebulex.Cache.count_all!/3.
Callback implementation for Nebulex.Cache.decr/3.
Callback implementation for Nebulex.Cache.decr/4.
Callback implementation for Nebulex.Cache.decr!/3.
Callback implementation for Nebulex.Cache.decr!/4.
Callback implementation for Nebulex.Cache.delete/2.
Callback implementation for Nebulex.Cache.delete/3.
Callback implementation for Nebulex.Cache.delete!/2.
Callback implementation for Nebulex.Cache.delete!/3.
Callback implementation for Nebulex.Cache.delete_all/2.
Callback implementation for Nebulex.Cache.delete_all/3.
Callback implementation for Nebulex.Cache.delete_all!/2.
Callback implementation for Nebulex.Cache.delete_all!/3.
Callback implementation for Nebulex.Cache.expire/3.
Callback implementation for Nebulex.Cache.expire/4.
Callback implementation for Nebulex.Cache.expire!/3.
Callback implementation for Nebulex.Cache.expire!/4.
Callback implementation for Nebulex.Cache.fetch/2.
Callback implementation for Nebulex.Cache.fetch/3.
Callback implementation for Nebulex.Cache.fetch!/2.
Callback implementation for Nebulex.Cache.fetch!/3.
Callback implementation for Nebulex.Cache.fetch_or_store/3.
Callback implementation for Nebulex.Cache.fetch_or_store/4.
Callback implementation for Nebulex.Cache.fetch_or_store!/3.
Callback implementation for Nebulex.Cache.fetch_or_store!/4.
A convenience function for retrieving the current generations.
Callback implementation for Nebulex.Cache.get/3.
Callback implementation for Nebulex.Cache.get/4.
Callback implementation for Nebulex.Cache.get!/3.
Callback implementation for Nebulex.Cache.get!/4.
Callback implementation for Nebulex.Cache.get_all/2.
Callback implementation for Nebulex.Cache.get_all/3.
Callback implementation for Nebulex.Cache.get_all!/2.
Callback implementation for Nebulex.Cache.get_all!/3.
Callback implementation for Nebulex.Cache.get_and_update/3.
Callback implementation for Nebulex.Cache.get_and_update/4.
Callback implementation for Nebulex.Cache.get_and_update!/3.
Callback implementation for Nebulex.Cache.get_and_update!/4.
Callback implementation for Nebulex.Cache.get_or_store/3.
Callback implementation for Nebulex.Cache.get_or_store/4.
Callback implementation for Nebulex.Cache.get_or_store!/3.
Callback implementation for Nebulex.Cache.get_or_store!/4.
Callback implementation for Nebulex.Cache.has_key?/2.
Callback implementation for Nebulex.Cache.has_key?/3.
Callback implementation for Nebulex.Cache.in_transaction?/1.
Callback implementation for Nebulex.Cache.in_transaction?/2.
Callback implementation for Nebulex.Cache.incr/3.
Callback implementation for Nebulex.Cache.incr/4.
Callback implementation for Nebulex.Cache.incr!/3.
Callback implementation for Nebulex.Cache.incr!/4.
Callback implementation for Nebulex.Cache.info/2.
Callback implementation for Nebulex.Cache.info/3.
Callback implementation for Nebulex.Cache.info!/2.
Callback implementation for Nebulex.Cache.info!/3.
Look up the cached decision for this exact request shape.
A convenience function for creating new generations.
A convenience function for retrieving the newer generation.
Callback implementation for Nebulex.Cache.put/3.
Callback implementation for Nebulex.Cache.put/4.
Callback implementation for Nebulex.Cache.put!/3.
Callback implementation for Nebulex.Cache.put!/4.
Callback implementation for Nebulex.Cache.put_all/2.
Callback implementation for Nebulex.Cache.put_all/3.
Callback implementation for Nebulex.Cache.put_all!/2.
Callback implementation for Nebulex.Cache.put_all!/3.
Callback implementation for Nebulex.Cache.put_new/3.
Callback implementation for Nebulex.Cache.put_new/4.
Callback implementation for Nebulex.Cache.put_new!/3.
Callback implementation for Nebulex.Cache.put_new!/4.
Callback implementation for Nebulex.Cache.put_new_all/2.
Callback implementation for Nebulex.Cache.put_new_all/3.
Callback implementation for Nebulex.Cache.put_new_all!/2.
Callback implementation for Nebulex.Cache.put_new_all!/3.
Callback implementation for Nebulex.Cache.register_event_listener/2.
Callback implementation for Nebulex.Cache.register_event_listener/3.
Callback implementation for Nebulex.Cache.register_event_listener!/2.
Callback implementation for Nebulex.Cache.register_event_listener!/3.
Callback implementation for Nebulex.Cache.replace/3.
Callback implementation for Nebulex.Cache.replace/4.
Callback implementation for Nebulex.Cache.replace!/3.
Callback implementation for Nebulex.Cache.replace!/4.
A convenience function for reset the GC interval.
Cache a decision for ttl_ms, or do nothing if the cache isn't running.
Callback implementation for Nebulex.Cache.stream/2.
Callback implementation for Nebulex.Cache.stream/3.
Callback implementation for Nebulex.Cache.stream!/2.
Callback implementation for Nebulex.Cache.stream!/3.
Callback implementation for Nebulex.Cache.take/2.
Callback implementation for Nebulex.Cache.take/3.
Callback implementation for Nebulex.Cache.take!/2.
Callback implementation for Nebulex.Cache.take!/3.
Callback implementation for Nebulex.Cache.touch/2.
Callback implementation for Nebulex.Cache.touch/3.
Callback implementation for Nebulex.Cache.touch!/2.
Callback implementation for Nebulex.Cache.touch!/3.
Callback implementation for Nebulex.Cache.transaction/2.
Callback implementation for Nebulex.Cache.transaction/3.
Callback implementation for Nebulex.Cache.ttl/2.
Callback implementation for Nebulex.Cache.ttl/3.
Callback implementation for Nebulex.Cache.ttl!/2.
Callback implementation for Nebulex.Cache.ttl!/3.
Callback implementation for Nebulex.Cache.unregister_event_listener/2.
Callback implementation for Nebulex.Cache.unregister_event_listener/3.
Callback implementation for Nebulex.Cache.unregister_event_listener!/2.
Callback implementation for Nebulex.Cache.unregister_event_listener!/3.
Callback implementation for Nebulex.Cache.update/4.
Callback implementation for Nebulex.Cache.update/5.
Callback implementation for Nebulex.Cache.update!/4.
Callback implementation for Nebulex.Cache.update!/5.
Types
@type decision() :: {:match, String.t()} | {:reject, :no_route | :method}
Functions
Is this request path short enough to be a cache key? The limits are on the segment count and the summed segment bytes, walked without allocating.
Callback implementation for Nebulex.Cache.count_all/2.
Callback implementation for Nebulex.Cache.count_all/3.
Callback implementation for Nebulex.Cache.count_all!/2.
Callback implementation for Nebulex.Cache.count_all!/3.
Callback implementation for Nebulex.Cache.decr/3.
Callback implementation for Nebulex.Cache.decr/4.
Callback implementation for Nebulex.Cache.decr!/3.
Callback implementation for Nebulex.Cache.decr!/4.
Callback implementation for Nebulex.Cache.delete/2.
Callback implementation for Nebulex.Cache.delete/3.
Callback implementation for Nebulex.Cache.delete!/2.
Callback implementation for Nebulex.Cache.delete!/3.
Callback implementation for Nebulex.Cache.delete_all/2.
Callback implementation for Nebulex.Cache.delete_all/3.
Callback implementation for Nebulex.Cache.delete_all!/2.
Callback implementation for Nebulex.Cache.delete_all!/3.
Callback implementation for Nebulex.Cache.expire/3.
Callback implementation for Nebulex.Cache.expire/4.
Callback implementation for Nebulex.Cache.expire!/3.
Callback implementation for Nebulex.Cache.expire!/4.
Callback implementation for Nebulex.Cache.fetch/2.
Callback implementation for Nebulex.Cache.fetch/3.
Callback implementation for Nebulex.Cache.fetch!/2.
Callback implementation for Nebulex.Cache.fetch!/3.
Callback implementation for Nebulex.Cache.fetch_or_store/3.
Callback implementation for Nebulex.Cache.fetch_or_store/4.
Callback implementation for Nebulex.Cache.fetch_or_store!/3.
Callback implementation for Nebulex.Cache.fetch_or_store!/4.
A convenience function for retrieving the current generations.
Callback implementation for Nebulex.Cache.get/3.
Callback implementation for Nebulex.Cache.get/4.
Callback implementation for Nebulex.Cache.get!/3.
Callback implementation for Nebulex.Cache.get!/4.
Callback implementation for Nebulex.Cache.get_all/2.
Callback implementation for Nebulex.Cache.get_all/3.
Callback implementation for Nebulex.Cache.get_all!/2.
Callback implementation for Nebulex.Cache.get_all!/3.
Callback implementation for Nebulex.Cache.get_and_update/3.
Callback implementation for Nebulex.Cache.get_and_update/4.
Callback implementation for Nebulex.Cache.get_and_update!/3.
Callback implementation for Nebulex.Cache.get_and_update!/4.
Callback implementation for Nebulex.Cache.get_or_store/3.
Callback implementation for Nebulex.Cache.get_or_store/4.
Callback implementation for Nebulex.Cache.get_or_store!/3.
Callback implementation for Nebulex.Cache.get_or_store!/4.
Callback implementation for Nebulex.Cache.has_key?/2.
Callback implementation for Nebulex.Cache.has_key?/3.
Callback implementation for Nebulex.Cache.in_transaction?/1.
Callback implementation for Nebulex.Cache.in_transaction?/2.
Callback implementation for Nebulex.Cache.incr/3.
Callback implementation for Nebulex.Cache.incr/4.
Callback implementation for Nebulex.Cache.incr!/3.
Callback implementation for Nebulex.Cache.incr!/4.
Callback implementation for Nebulex.Cache.info/2.
Callback implementation for Nebulex.Cache.info/3.
Callback implementation for Nebulex.Cache.info!/2.
Callback implementation for Nebulex.Cache.info!/3.
@spec lookup(atom(), pos_integer(), String.t(), [String.t()]) :: {:ok, decision()} | :error
Look up the cached decision for this exact request shape.
A convenience function for creating new generations.
A convenience function for retrieving the newer generation.
Callback implementation for Nebulex.Cache.put/3.
Callback implementation for Nebulex.Cache.put/4.
Callback implementation for Nebulex.Cache.put!/3.
Callback implementation for Nebulex.Cache.put!/4.
Callback implementation for Nebulex.Cache.put_all/2.
Callback implementation for Nebulex.Cache.put_all/3.
Callback implementation for Nebulex.Cache.put_all!/2.
Callback implementation for Nebulex.Cache.put_all!/3.
Callback implementation for Nebulex.Cache.put_new/3.
Callback implementation for Nebulex.Cache.put_new/4.
Callback implementation for Nebulex.Cache.put_new!/3.
Callback implementation for Nebulex.Cache.put_new!/4.
Callback implementation for Nebulex.Cache.put_new_all/2.
Callback implementation for Nebulex.Cache.put_new_all/3.
Callback implementation for Nebulex.Cache.put_new_all!/2.
Callback implementation for Nebulex.Cache.put_new_all!/3.
Callback implementation for Nebulex.Cache.register_event_listener/2.
Callback implementation for Nebulex.Cache.register_event_listener/3.
Callback implementation for Nebulex.Cache.register_event_listener!/2.
Callback implementation for Nebulex.Cache.register_event_listener!/3.
Callback implementation for Nebulex.Cache.replace/3.
Callback implementation for Nebulex.Cache.replace/4.
Callback implementation for Nebulex.Cache.replace!/3.
Callback implementation for Nebulex.Cache.replace!/4.
A convenience function for reset the GC interval.
@spec store( atom(), pos_integer(), String.t(), [String.t()], decision(), pos_integer() ) :: :ok
Cache a decision for ttl_ms, or do nothing if the cache isn't running.
Callback implementation for Nebulex.Cache.stream/2.
Callback implementation for Nebulex.Cache.stream/3.
Callback implementation for Nebulex.Cache.stream!/2.
Callback implementation for Nebulex.Cache.stream!/3.
Callback implementation for Nebulex.Cache.take/2.
Callback implementation for Nebulex.Cache.take/3.
Callback implementation for Nebulex.Cache.take!/2.
Callback implementation for Nebulex.Cache.take!/3.
Callback implementation for Nebulex.Cache.touch/2.
Callback implementation for Nebulex.Cache.touch/3.
Callback implementation for Nebulex.Cache.touch!/2.
Callback implementation for Nebulex.Cache.touch!/3.
Callback implementation for Nebulex.Cache.transaction/2.
Callback implementation for Nebulex.Cache.transaction/3.
Callback implementation for Nebulex.Cache.ttl/2.
Callback implementation for Nebulex.Cache.ttl/3.
Callback implementation for Nebulex.Cache.ttl!/2.
Callback implementation for Nebulex.Cache.ttl!/3.
Callback implementation for Nebulex.Cache.unregister_event_listener/2.
Callback implementation for Nebulex.Cache.unregister_event_listener/3.
Callback implementation for Nebulex.Cache.unregister_event_listener!/2.
Callback implementation for Nebulex.Cache.unregister_event_listener!/3.
Callback implementation for Nebulex.Cache.update/4.
Callback implementation for Nebulex.Cache.update/5.
Callback implementation for Nebulex.Cache.update!/4.
Callback implementation for Nebulex.Cache.update!/5.