Normandy.Cluster (normandy v2.2.0)

View Source

Optional convenience for wiring the distributed-session infra (Tier 2) into a host supervision tree. Returns child specs for:

  • the Horde registry (SessionRegistry.Horde, members: :auto),
  • the Horde supervisor (Turn.Supervisor.Horde, members: :auto),
  • the Turn.ResumeReaper (only when both :store and :template_provider are supplied — eager handoff needs them), and
  • an optional libcluster Cluster.Supervisor (only when :topologies is given AND libcluster is a dependency of the host app).

Cluster formation remains the host's choice — this is sugar, not a requirement. Normandy does NOT depend on libcluster; the Cluster.Supervisor spec is added only if the running system has it loaded (a runtime check), so hosts that wire their own clustering (or none) are unaffected.

Example (host application.ex)

children = [
  MyApp.Repo,
  {Normandy.Behaviours.AgentTemplate.Catalog, name: MyApp.AgentTemplates}
] ++
  Normandy.Cluster.child_specs(
    registry: MyApp.SessionRegistry,
    supervisor: MyApp.TurnSupervisor,
    store: {Normandy.Behaviours.SessionStore.Postgres, MyApp.Repo},
    template_provider: {Normandy.Behaviours.AgentTemplate.Catalog, MyApp.AgentTemplates},
    topologies: Application.get_env(:libcluster, :topologies, [])
  )

Supervisor.start_link(children, strategy: :one_for_one)

Summary

Functions

Build the distributed-session child specs.

Child specs for the Redis combo (Redis registry + Redis store + local supervisor + reaper) — Redis as the single distributed dependency. :template_provider enables the ResumeReaper for eager handoff. Cross-node routing still uses Erlang distribution. redis_handles/1 returns the registry and store to give Turn.Session.new/1.

The {module, handle} pairs of the registry and store that redis_child_specs/1 starts for the same options: pass them to Normandy.Agents.Turn.Session.new/1 as :registry and :store. Starts and calls nothing.

Create the Mnesia store tables (host setup, not a child spec). Thin pass-through to SessionStore.Mnesia.create_tables/1 — call once at boot before serving sessions.

Functions

child_specs(opts)

@spec child_specs(keyword()) :: [
  Supervisor.child_spec() | :supervisor.child_spec() | map()
]

Build the distributed-session child specs.

Options

  • :registry (atom/0) - Required. The Horde registry's name.

  • :supervisor (atom/0) - Required. The Horde supervisor's name.

  • :store ({module, handle}) - The SessionStore; with :template_provider, starts the reaper.

  • :template_provider ({module, handle}) - The AgentTemplate; with :store, starts the reaper.

  • :topologies (keyword/0) - libcluster topologies; adds Cluster.Supervisor when libcluster is loaded. The default value is [].

redis_child_specs(opts)

@spec redis_child_specs(keyword()) :: [Supervisor.child_spec() | map()]

Child specs for the Redis combo (Redis registry + Redis store + local supervisor + reaper) — Redis as the single distributed dependency. :template_provider enables the ResumeReaper for eager handoff. Cross-node routing still uses Erlang distribution. redis_handles/1 returns the registry and store to give Turn.Session.new/1.

The registry and the store share the :redix connection, except for the store's waited writes. When config :normandy, :redis_wait asks for replicas (read here, once), the specs also start :wait_connections Redix connections, named :"<redix name>.wait.<i>", and the store runs each waited write and its WAIT on one of them (see Normandy.Behaviours.SessionStore.Redis). With :store_redix, the store uses that connection for everything and no pool starts.

Options

  • :redix (keyword/0) - Required. Options for the Redix connection; must include :name.

  • :namespace (String.t/0) - Required. The key namespace for the registry and the store.

  • :registry (atom/0) - Required. The Redis registry owner's name.

  • :supervisor (atom/0) - Required. The local Turn.Supervisor's name.

  • :template_provider ({module, handle}) - The AgentTemplate; starts the reaper.

  • :store_redix (keyword/0) - Options (with :name) for a Redix connection the store uses alone, for every command and every WAIT, instead of :redix's and a WAIT pool. Share it with nothing: a WAIT stalls it.

  • :wait_connections (pos_integer/0) - How many connections the store's WAIT pool opens (default 4); only when config :normandy, :redis_wait asks for replicas and without :store_redix. Given when :redis_wait asks for none, it raises ArgumentError.

redis_handles(opts)

@spec redis_handles(keyword()) :: %{
  registry: {module(), term()},
  store: {module(), term()}
}

The {module, handle} pairs of the registry and store that redis_child_specs/1 starts for the same options: pass them to Normandy.Agents.Turn.Session.new/1 as :registry and :store. Starts and calls nothing.

Options

The options of redis_child_specs/1.

setup_mnesia_store!(opts)

@spec setup_mnesia_store!(keyword()) :: :ok

Create the Mnesia store tables (host setup, not a child spec). Thin pass-through to SessionStore.Mnesia.create_tables/1 — call once at boot before serving sessions.

Options

The options of Normandy.Behaviours.SessionStore.Mnesia.create_tables/1.