Dsxir.Settings (dsxir v0.1.0)

Copy Markdown

Three-layer settings stack: globals (:persistent_term), per-process scope (process dict), per-call opts (passed as args).

  • configure/1 writes globals. Call once at boot.
  • context/2 pushes a scoped frame for the duration of fun.().
  • snapshot/0 captures the current globals+stack; run/2 replays them in a worker.
  • resolve/2 looks up a key: stack top-down, then globals, then the provided default.

tenant_* keys and :lm tuples whose config carries a non-nil :api_key are rejected by configure/1 with a Logger.warning. tenant_* keys nested inside :metadata are stripped from the map with a Logger.warning; non-tenant keys in the same map pass through unchanged. Per-request tenant data flows through context/2. The :lm field has shape nil | {impl_module :: module(), config :: keyword()} (see Dsxir.LM); credentials live in the config keyword list, not at the top level.

Summary

Functions

Install globals into :persistent_term. Merges with whatever is currently stored; unknown keys raise Dsxir.Errors.Invalid.Configuration. tenant_* keys and :lm tuples whose config carries a non-nil :api_key are dropped with a warning. tenant_* keys nested inside :metadata are stripped from the map (other keys preserved).

Push a scoped frame for the duration of fun.(). Restored via try/after.

Architectural defaults installed at application boot.

Walk the stack top-down, then globals, then return the default.

Replay a snapshot in the calling process for the duration of fun.().

Snapshot the live globals and scope stack for replay in another process.

Types

t()

@type t() :: %Dsxir.Settings{
  adapter: nil | module(),
  cache: boolean(),
  call_plugs: list(),
  callbacks: list(),
  lm: nil | {module(), keyword()},
  metadata: map()
}

Functions

configure(opts)

@spec configure(Enumerable.t()) :: :ok

Install globals into :persistent_term. Merges with whatever is currently stored; unknown keys raise Dsxir.Errors.Invalid.Configuration. tenant_* keys and :lm tuples whose config carries a non-nil :api_key are dropped with a warning. tenant_* keys nested inside :metadata are stripped from the map (other keys preserved).

context(frame, fun)

@spec context(Enumerable.t(), (-> any())) :: any()

Push a scoped frame for the duration of fun.(). Restored via try/after.

default_globals()

@spec default_globals() :: map()

Architectural defaults installed at application boot.

resolve(key, default \\ nil)

@spec resolve(atom(), term()) :: term()

Walk the stack top-down, then globals, then return the default.

run(map, fun)

@spec run(%{globals: map(), stack: [map()]}, (-> any())) :: any()

Replay a snapshot in the calling process for the duration of fun.().

Writes globals into :persistent_term only when the snapshot's globals differ from the live globals — :persistent_term.put/2 triggers a system-wide GC of every process holding references and is designed for write-once-read-many data, so fan-out workers (e.g. Dsxir.Predictor.Parallel) replaying the same snapshot must not pay that cost N times. The scope stack is always restored on exit; globals are not. Intended for short-lived worker processes that have no prior globals worth preserving. Do not use to "temporarily" swap globals in a long-lived process.

snapshot()

@spec snapshot() :: %{globals: map(), stack: [map()]}

Snapshot the live globals and scope stack for replay in another process.