ISRPlug (ISRPlug v0.1.0)

View Source

A generic Plug implementing an Incremental Static Regeneration (ISR) pattern.

This plug allows serving cached data (fresh or stale) quickly while triggering non-blocking background tasks to refresh expired data. It's designed to be flexible and reusable in Phoenix applications.

Configuration

The plug is configured via options passed during the plug call in the router:

plug ISRPlug,
  # --- Required ---
  fetch_fun: &YourModule.your_fetch_function/1,
  apply_fun: &YourModule.your_apply_function/2,

  # --- Optional ---
  extract_data_fun: &YourModule.your_extract_function/1,
  cache_key_fun: &YourModule.your_cache_key_function/1,
  ets_table: :my_specific_isr_cache,
  cache_ttl_ms: 60_000, # 1 minute
  stale_serving_ttl_ms: 3_600_000, # 1 hour
  error_handler_fun: &YourModule.your_error_handler/2

See the function documentation for init/1 for details on each option.

Summary

Functions

Processes the connection according to the ISR logic.

Initializes the plug with configuration options.

Functions

call(conn, opts)

Processes the connection according to the ISR logic.

  1. Extracts data and determines the cache key using configured functions.
  2. Checks the ETS cache.
  3. Handles cache hits (fresh or stale).
  4. If stale, serves stale data and triggers a background refresh task.
  5. Handles cache misses or expired stale TTL by fetching synchronously.
  6. If synchronous fetch fails, calls the error handler.
  7. If data is available (fresh, stale, or newly fetched), applies it using the configured function.
  8. Returns the (potentially modified) connection.

init(opts)

Initializes the plug with configuration options.

Options

  • :fetch_fun (required): A 1-arity function (extracted_data :: any()) -> {:ok, value :: any()} | {:error, reason :: any()}. Performs the data retrieval.

  • :apply_fun (required): A 2-arity function (conn :: Plug.Conn.t(), value :: any()) -> Plug.Conn.t(). Applies the successfully retrieved value (fresh or stale) to the connection. Must return a Plug.Conn.t().

  • :extract_data_fun (optional): A 1-arity function (conn :: Plug.Conn.t()) -> any(). Extracts necessary data from the conn to be passed to :fetch_fun. Defaults to fn _conn -> %{} end.

  • :cache_key_fun (optional): A 1-arity function (conn :: Plug.Conn.t()) -> term(). Generates a unique ETS key based on the connection. Defaults to fn _conn -> :isr_plug_default_key end. Ensure this generates distinct keys if the fetched data varies based on connection properties.

  • :ets_table (optional): Atom name for the ETS table. Defaults to isr_plug_cache. Use distinct names if using the plug multiple times for different purposes.

  • :cache_ttl_ms (optional): Integer milliseconds for how long data is considered fresh. Defaults to 60000 (1 minute).

  • :stale_serving_ttl_ms (optional): Integer milliseconds after expiry during which stale data can be served while refreshing. Defaults to 3600000 (1 hour).

  • :error_handler_fun (optional): A 2-arity function (conn :: Plug.Conn.t(), reason :: any()) -> Plug.Conn.t(). Called only when a synchronous fetch fails. Defaults to a function that logs the error and returns the original conn.

This function also initializes the specified ETS table if it doesn't already exist.