Ankusa.Routes.Cache (ankusa v0.7.0)

Copy Markdown View Source

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.delete/2.

Callback implementation for Nebulex.Cache.delete!/2.

Callback implementation for Nebulex.Cache.fetch/2.

Callback implementation for Nebulex.Cache.fetch!/2.

A convenience function for retrieving the current generations.

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!/3.

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.take/2.

Callback implementation for Nebulex.Cache.take!/2.

Callback implementation for Nebulex.Cache.touch/2.

Callback implementation for Nebulex.Cache.touch!/2.

Callback implementation for Nebulex.Cache.ttl/2.

Callback implementation for Nebulex.Cache.ttl/3.

Callback implementation for Nebulex.Cache.ttl!/2.

Types

decision()

@type decision() :: {:match, String.t()} | {:reject, :no_route | :method}

Functions

cacheable?(segments)

@spec cacheable?([String.t()]) :: boolean()

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.

count_all(query_spec \\ [], opts \\ [])

Callback implementation for Nebulex.Cache.count_all/2.

count_all(dynamic_cache, query_spec, opts)

Callback implementation for Nebulex.Cache.count_all/3.

count_all!(query_spec \\ [], opts \\ [])

Callback implementation for Nebulex.Cache.count_all!/2.

count_all!(dynamic_cache, query_spec, opts)

Callback implementation for Nebulex.Cache.count_all!/3.

decr(key, amount \\ 1, opts \\ [])

Callback implementation for Nebulex.Cache.decr/3.

decr(dynamic_cache, key, amount, opts)

Callback implementation for Nebulex.Cache.decr/4.

decr!(key, amount \\ 1, opts \\ [])

Callback implementation for Nebulex.Cache.decr!/3.

decr!(dynamic_cache, key, amount, opts)

Callback implementation for Nebulex.Cache.decr!/4.

delete(key, opts \\ [])

Callback implementation for Nebulex.Cache.delete/2.

delete(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.delete/3.

delete!(key, opts \\ [])

Callback implementation for Nebulex.Cache.delete!/2.

delete!(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.delete!/3.

delete_all(query_spec \\ [], opts \\ [])

Callback implementation for Nebulex.Cache.delete_all/2.

delete_all(dynamic_cache, query_spec, opts)

Callback implementation for Nebulex.Cache.delete_all/3.

delete_all!(query_spec \\ [], opts \\ [])

Callback implementation for Nebulex.Cache.delete_all!/2.

delete_all!(dynamic_cache, query_spec, opts)

Callback implementation for Nebulex.Cache.delete_all!/3.

expire(key, ttl, opts \\ [])

Callback implementation for Nebulex.Cache.expire/3.

expire(dynamic_cache, key, ttl, opts)

Callback implementation for Nebulex.Cache.expire/4.

expire!(key, ttl, opts \\ [])

Callback implementation for Nebulex.Cache.expire!/3.

expire!(dynamic_cache, key, ttl, opts)

Callback implementation for Nebulex.Cache.expire!/4.

fetch(key, opts \\ [])

Callback implementation for Nebulex.Cache.fetch/2.

fetch(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.fetch/3.

fetch!(key, opts \\ [])

Callback implementation for Nebulex.Cache.fetch!/2.

fetch!(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.fetch!/3.

fetch_or_store(key, fun, opts \\ [])

Callback implementation for Nebulex.Cache.fetch_or_store/3.

fetch_or_store(dynamic_cache, key, fun, opts)

Callback implementation for Nebulex.Cache.fetch_or_store/4.

fetch_or_store!(key, fun, opts \\ [])

Callback implementation for Nebulex.Cache.fetch_or_store!/3.

fetch_or_store!(dynamic_cache, key, fun, opts)

Callback implementation for Nebulex.Cache.fetch_or_store!/4.

generations()

A convenience function for retrieving the current generations.

get(key, default \\ nil, opts \\ [])

Callback implementation for Nebulex.Cache.get/3.

get(dynamic_cache, key, default, opts)

Callback implementation for Nebulex.Cache.get/4.

get!(key, default \\ nil, opts \\ [])

Callback implementation for Nebulex.Cache.get!/3.

get!(dynamic_cache, key, default, opts)

Callback implementation for Nebulex.Cache.get!/4.

get_all(query_spec \\ [], opts \\ [])

Callback implementation for Nebulex.Cache.get_all/2.

get_all(dynamic_cache, query_spec, opts)

Callback implementation for Nebulex.Cache.get_all/3.

get_all!(query_spec \\ [], opts \\ [])

Callback implementation for Nebulex.Cache.get_all!/2.

get_all!(dynamic_cache, query_spec, opts)

Callback implementation for Nebulex.Cache.get_all!/3.

get_and_update(key, fun, opts \\ [])

Callback implementation for Nebulex.Cache.get_and_update/3.

get_and_update(dynamic_cache, key, fun, opts)

Callback implementation for Nebulex.Cache.get_and_update/4.

get_and_update!(key, fun, opts \\ [])

Callback implementation for Nebulex.Cache.get_and_update!/3.

get_and_update!(dynamic_cache, key, fun, opts)

Callback implementation for Nebulex.Cache.get_and_update!/4.

get_or_store(key, fun, opts \\ [])

Callback implementation for Nebulex.Cache.get_or_store/3.

get_or_store(dynamic_cache, key, fun, opts)

Callback implementation for Nebulex.Cache.get_or_store/4.

get_or_store!(key, fun, opts \\ [])

Callback implementation for Nebulex.Cache.get_or_store!/3.

get_or_store!(dynamic_cache, key, fun, opts)

Callback implementation for Nebulex.Cache.get_or_store!/4.

has_key?(key, opts \\ [])

Callback implementation for Nebulex.Cache.has_key?/2.

has_key?(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.has_key?/3.

in_transaction?(opts \\ [])

Callback implementation for Nebulex.Cache.in_transaction?/1.

in_transaction?(dynamic_cache, opts)

Callback implementation for Nebulex.Cache.in_transaction?/2.

incr(key, amount \\ 1, opts \\ [])

Callback implementation for Nebulex.Cache.incr/3.

incr(dynamic_cache, key, amount, opts)

Callback implementation for Nebulex.Cache.incr/4.

incr!(key, amount \\ 1, opts \\ [])

Callback implementation for Nebulex.Cache.incr!/3.

incr!(dynamic_cache, key, amount, opts)

Callback implementation for Nebulex.Cache.incr!/4.

info(spec \\ :all, opts \\ [])

Callback implementation for Nebulex.Cache.info/2.

info(dynamic_cache, spec, opts)

Callback implementation for Nebulex.Cache.info/3.

info!(spec \\ :all, opts \\ [])

Callback implementation for Nebulex.Cache.info!/2.

info!(dynamic_cache, spec, opts)

Callback implementation for Nebulex.Cache.info!/3.

lookup(instance, epoch, method, segments)

@spec lookup(atom(), pos_integer(), String.t(), [String.t()]) ::
  {:ok, decision()} | :error

Look up the cached decision for this exact request shape.

new_generation(opts \\ [])

A convenience function for creating new generations.

newer_generation()

A convenience function for retrieving the newer generation.

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

Callback implementation for Nebulex.Cache.put/3.

put(dynamic_cache, key, value, opts)

Callback implementation for Nebulex.Cache.put/4.

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

Callback implementation for Nebulex.Cache.put!/3.

put!(dynamic_cache, key, value, opts)

Callback implementation for Nebulex.Cache.put!/4.

put_all(entries, opts \\ [])

Callback implementation for Nebulex.Cache.put_all/2.

put_all(dynamic_cache, entries, opts)

Callback implementation for Nebulex.Cache.put_all/3.

put_all!(entries, opts \\ [])

Callback implementation for Nebulex.Cache.put_all!/2.

put_all!(dynamic_cache, entries, opts)

Callback implementation for Nebulex.Cache.put_all!/3.

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

Callback implementation for Nebulex.Cache.put_new/3.

put_new(dynamic_cache, key, value, opts)

Callback implementation for Nebulex.Cache.put_new/4.

put_new!(key, value, opts \\ [])

Callback implementation for Nebulex.Cache.put_new!/3.

put_new!(dynamic_cache, key, value, opts)

Callback implementation for Nebulex.Cache.put_new!/4.

put_new_all(entries, opts \\ [])

Callback implementation for Nebulex.Cache.put_new_all/2.

put_new_all(dynamic_cache, entries, opts)

Callback implementation for Nebulex.Cache.put_new_all/3.

put_new_all!(entries, opts \\ [])

Callback implementation for Nebulex.Cache.put_new_all!/2.

put_new_all!(dynamic_cache, entries, opts)

Callback implementation for Nebulex.Cache.put_new_all!/3.

register_event_listener(listener, opts \\ [])

Callback implementation for Nebulex.Cache.register_event_listener/2.

register_event_listener(dynamic_cache, listener, opts)

Callback implementation for Nebulex.Cache.register_event_listener/3.

register_event_listener!(listener, opts \\ [])

Callback implementation for Nebulex.Cache.register_event_listener!/2.

register_event_listener!(dynamic_cache, listener, opts)

Callback implementation for Nebulex.Cache.register_event_listener!/3.

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

Callback implementation for Nebulex.Cache.replace/3.

replace(dynamic_cache, key, value, opts)

Callback implementation for Nebulex.Cache.replace/4.

replace!(key, value, opts \\ [])

Callback implementation for Nebulex.Cache.replace!/3.

replace!(dynamic_cache, key, value, opts)

Callback implementation for Nebulex.Cache.replace!/4.

reset_gc_interval()

A convenience function for reset the GC interval.

store(instance, epoch, method, segments, decision, ttl_ms)

@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.

stream(query_spec \\ [], opts \\ [])

Callback implementation for Nebulex.Cache.stream/2.

stream(dynamic_cache, query_spec, opts)

Callback implementation for Nebulex.Cache.stream/3.

stream!(query_spec \\ [], opts \\ [])

Callback implementation for Nebulex.Cache.stream!/2.

stream!(dynamic_cache, query_spec, opts)

Callback implementation for Nebulex.Cache.stream!/3.

take(key, opts \\ [])

Callback implementation for Nebulex.Cache.take/2.

take(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.take/3.

take!(key, opts \\ [])

Callback implementation for Nebulex.Cache.take!/2.

take!(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.take!/3.

touch(key, opts \\ [])

Callback implementation for Nebulex.Cache.touch/2.

touch(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.touch/3.

touch!(key, opts \\ [])

Callback implementation for Nebulex.Cache.touch!/2.

touch!(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.touch!/3.

transaction(fun, opts \\ [])

Callback implementation for Nebulex.Cache.transaction/2.

transaction(dynamic_cache, fun, opts)

Callback implementation for Nebulex.Cache.transaction/3.

ttl(key, opts \\ [])

Callback implementation for Nebulex.Cache.ttl/2.

ttl(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.ttl/3.

ttl!(key, opts \\ [])

Callback implementation for Nebulex.Cache.ttl!/2.

ttl!(dynamic_cache, key, opts)

Callback implementation for Nebulex.Cache.ttl!/3.

unregister_event_listener(id, opts \\ [])

Callback implementation for Nebulex.Cache.unregister_event_listener/2.

unregister_event_listener(dynamic_cache, id, opts)

Callback implementation for Nebulex.Cache.unregister_event_listener/3.

unregister_event_listener!(id, opts \\ [])

Callback implementation for Nebulex.Cache.unregister_event_listener!/2.

unregister_event_listener!(dynamic_cache, id, opts)

Callback implementation for Nebulex.Cache.unregister_event_listener!/3.

update(key, initial, fun, opts \\ [])

Callback implementation for Nebulex.Cache.update/4.

update(dynamic_cache, key, initial, fun, opts)

Callback implementation for Nebulex.Cache.update/5.

update!(key, initial, fun, opts \\ [])

Callback implementation for Nebulex.Cache.update!/4.

update!(dynamic_cache, key, initial, fun, opts)

Callback implementation for Nebulex.Cache.update!/5.