lib/cloister/node.ex

defmodule Cloister.Node do
  @moduledoc """
  The abstraction level allowing milticalls and multicasts across the whole cluster.
  """

  use GenServer

  @doc false
  def start_link(opts \\ []) do
    {state, opts} = Keyword.pop(opts, :state, [])

    GenServer.start_link(
      __MODULE__,
      state,
      Keyword.put_new(opts, :name, __MODULE__)
    )
  end

  @impl GenServer
  @doc false
  def init(state), do: {:ok, state}

  @spec multicast(nodes :: [node()], name :: GenServer.name(), request :: term()) :: :abcast
  @doc """
  Casts the request to all the nodes connected to this node
  """
  def multicast(nodes \\ [node() | Node.list()], name, request),
    do: :rpc.eval_everywhere(nodes, GenServer, :cast, [name, request])

  @spec multicall(nodes :: [node()], name :: GenServer.name(), request :: term()) :: [term()]
  @doc """
  Casts the request to all the nodes passed as a parameter.
  """
  def multicall(nodes \\ [node() | Node.list()], name, request) do
    with {replies, _} <- :rpc.multicall(nodes, GenServer, :call, [name, request]), do: replies
  end
end