lib/process_hub/initializer.ex

defmodule ProcessHub.Initializer do
  @moduledoc """
  The main `ProcessHub` initializer supervisor module.

  This module is responsible for starting all the child processes of `ProcessHub`.
  """

  alias ProcessHub.Utility.Name
  alias ProcessHub.Service.ProcessRegistry
  alias :blockade, as: Blockade

  use Supervisor

  @doc "Starts a `ProcessHub` instance with all its children."
  @spec start_link(ProcessHub.t()) :: {:ok, pid()} | {:error, term()}
  def start_link(hub_settings) when is_struct(hub_settings) do
    Supervisor.start_link(__MODULE__, hub_settings, name: Name.initializer(hub_settings.hub_id))
  end

  def start_link(_), do: {:error, :expected_hub_settings}

  @doc "Starts a `ProcessHub` instance with all its children."
  @spec stop(atom()) :: :ok | {:error, :not_alive}
  def stop(hub_id) do
    if ProcessHub.is_alive?(hub_id) do
      Supervisor.stop(Name.initializer(hub_id))
    else
      {:error, :not_alive}
    end
  end

  @impl true
  def init(%ProcessHub{hub_id: hub_id} = hub) do
    setup_tables(hub_id)

    managers = %{
      coordinator: Name.coordinator(hub_id),
      local_event_queue: Name.local_event_queue(hub_id),
      global_event_queue: Name.global_event_queue(hub_id),
      distributed_supervisor: Name.distributed_supervisor(hub_id),
      task_supervisor: Name.task_supervisor(hub_id)
    }

    children = [
      {Blockade, %{name: managers.local_event_queue}},
      {Blockade, %{name: managers.global_event_queue}},
      {ProcessHub.DistributedSupervisor, {hub_id, managers}},
      {Task.Supervisor, name: managers.task_supervisor},
      {ProcessHub.Coordinator, {hub_id, hub, managers}},
      {ProcessHub.WorkerQueue, Name.worker_queue(hub_id)}
    ]

    opts = [strategy: :one_for_one]

    case Node.alive?() do
      true -> Supervisor.init(children, opts)
      false -> {:error, :local_node_not_alive}
    end
  end

  defp setup_tables(hub_id) do
    :ets.new(ProcessRegistry.registry_name(hub_id), [:set, :public, :named_table])
    :ets.new(hub_id, [:set, :public, :named_table])
  end
end