ExAtlas.Fly.Tokens.Supervisor (ExAtlas v0.5.0)

Copy Markdown View Source

Supervises the Fly-tokens trio: Registry + ETSOwner + DynamicSupervisor.

Topology (:rest_for_one):

ExAtlas.Fly.Tokens.Supervisor
 Registry   (ExAtlas.Fly.Tokens.Registry)     keyed by app_name
 ETSOwner   (ExAtlas.Fly.Tokens.ETSOwner)     owns the shared table
 DynamicSupervisor (ExAtlas.Fly.Tokens.DynamicSupervisor)
     AppServer for "my-app"
     AppServer for "other-app"
     ...

Strategy rationale:

  • Registry crash: everything restarts. Children are registered there, so a stale registry would be useless anyway.
  • ETSOwner crash: :rest_for_one rebuilds the DynamicSupervisor too — every AppServer restarts, cache is empty, first call per app re-reads from storage. Clean blast-radius.
  • AppServer crash: stays scoped to that one app (DynamicSupervisor :one_for_one, max_restarts: 20, max_seconds: 60).

Opts

Production uses fixed module-level names for the three children. Tests override every name to isolate the trio per test; see test/ex_atlas/fly/tokens/tokens_test.exs.

  • :name — supervisor name (default __MODULE__).
  • :registry — Registry name (default ExAtlas.Fly.Tokens.Registry).
  • :ets_owner — ETSOwner name (default ExAtlas.Fly.Tokens.ETSOwner).
  • :dynamic_sup — DynamicSupervisor name (default ExAtlas.Fly.Tokens.DynamicSupervisor).
  • :task_supTask.Supervisor name used by AppServers to offload blocking persist writes (default ExAtlas.Fly.Tokens.TaskSupervisor).
  • :ets_table — ETS table name (default :ex_atlas_fly_tokens).
  • :app_server_defaults — keyword passed into every AppServer (cmd_fn, config_file_fn, storage_mod, ttl_seconds, cli_timeout_ms). Mostly for tests.

Summary

Functions

Returns a specification to start this module under a supervisor.

Resolve the AppServer pid for app_name, starting one under the DynamicSupervisor if none exists.

Look up the AppServer pid for app_name, or nil if none is running.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

resolve_app_server(app_name, opts \\ [])

@spec resolve_app_server(
  String.t(),
  keyword()
) :: {:ok, pid()} | {:error, term()}

Resolve the AppServer pid for app_name, starting one under the DynamicSupervisor if none exists.

Handles the {:error, {:already_started, pid}} race where two processes both call start_child before either Registry.register call returns.

start_link(opts \\ [])

whereis_app_server(app_name, opts \\ [])

@spec whereis_app_server(
  String.t(),
  keyword()
) :: pid() | nil

Look up the AppServer pid for app_name, or nil if none is running.