Jido.Signal.Router.Cache (Jido Signal v2.0.0-rc.0)

View Source

Optional persistent_term caching for Router tries.

This module provides a caching layer for router tries using Erlang's :persistent_term storage. This is useful for hot-path routing where you want to avoid the overhead of passing the router struct through function calls.

When to Use

  • High-throughput signal routing (10k+ signals/sec)
  • Router configuration that changes infrequently
  • When you need to share a router across processes without passing the struct

When NOT to Use

  • Routers that change frequently (persistent_term has global GC on update)
  • Short-lived routers
  • When you already have the router struct available

Usage

# Create and cache a router
{:ok, router} = Router.new([{"user.created", MyHandler}], cache_id: :my_router)

# Route using the cached trie (avoids struct lookup)
{:ok, handlers} = Router.Cache.route(:my_router, signal)

# Manually cache an existing router
:ok = Router.Cache.put(:my_router, router)

# Get cached router
{:ok, router} = Router.Cache.get(:my_router)

# Delete cached router
:ok = Router.Cache.delete(:my_router)

Multiple Routers

Each router is identified by a unique cache_id (atom or tuple). This allows multiple routers to coexist in the cache:

{:ok, router1} = Router.new(routes1, cache_id: :user_router)
{:ok, router2} = Router.new(routes2, cache_id: :payment_router)

Performance Considerations

  • Reads from persistent_term are extremely fast (no copying)
  • Writes trigger a global garbage collection of all persistent_terms
  • Best for routers that are configured at startup and rarely change

Summary

Functions

Checks if a router is cached.

Removes a router from the cache.

Retrieves a cached router trie and wraps it in a Router struct.

Lists all cached router IDs.

Stores a router's trie in persistent_term cache.

Routes a signal using a cached router trie directly.

Updates a cached router with new routes.

Types

cache_id()

@type cache_id() :: atom() | {atom(), term()}

Functions

cached?(cache_id)

@spec cached?(cache_id()) :: boolean()

Checks if a router is cached.

Parameters

  • cache_id: The identifier to check

Returns

  • true if cached, false otherwise

delete(cache_id)

@spec delete(cache_id()) :: :ok

Removes a router from the cache.

Parameters

  • cache_id: The identifier used when caching the router

Returns

  • :ok (always succeeds, even if key didn't exist)

Example

:ok = Router.Cache.delete(:my_router)

get(cache_id)

@spec get(cache_id()) :: {:ok, map()} | {:error, :not_found}

Retrieves a cached router trie and wraps it in a Router struct.

Parameters

  • cache_id: The identifier used when caching the router

Returns

  • {:ok, %Router{}} if found
  • {:error, :not_found} if not cached

Example

{:ok, router} = Router.Cache.get(:my_router)

list_cached()

@spec list_cached() :: [cache_id()]

Lists all cached router IDs.

Note: This iterates all persistent_terms, so use sparingly.

Returns

  • List of cache_ids for routers

put(cache_id, map)

@spec put(cache_id(), map()) :: :ok

Stores a router's trie in persistent_term cache.

Parameters

  • cache_id: Unique identifier for this cached router (atom or tuple)
  • router: The Router struct to cache (or any struct with a :trie field)

Returns

  • :ok

Example

:ok = Router.Cache.put(:my_router, router)

route(cache_id, signal)

@spec route(cache_id(), Jido.Signal.t()) :: {:ok, [term()]} | {:error, term()}

Routes a signal using a cached router trie directly.

This is the most efficient way to route signals when the router is cached, as it avoids the overhead of reconstructing the Router struct.

Parameters

  • cache_id: The identifier of the cached router
  • signal: The signal to route

Returns

  • {:ok, [targets]} - List of matching targets
  • {:error, :not_cached} - Router not in cache
  • {:error, reason} - Routing error

Example

{:ok, handlers} = Router.Cache.route(:my_router, signal)

update(cache_id, routes)

@spec update(cache_id(), term()) :: {:ok, map()} | {:error, term()}

Updates a cached router with new routes.

This is a convenience function that:

  1. Gets the cached router (or creates empty)
  2. Adds the new routes
  3. Updates the cache

Parameters

  • cache_id: The identifier of the cached router
  • routes: Routes to add (same format as Router.add/2)

Returns

  • {:ok, updated_router} on success
  • {:error, reason} on failure