Distribunator

Utilities supporting process distribution across nodes and node connections.

Installation

The package can be installed by adding distribunator to your list of dependencies in mix.exs:

def deps do
  [
    {:distribunator, "~> 0.1"}
  ]
end

Use

Distribunator consists of two components: The Distribunator.Manager GenServer and the Distribunator.Distributed utility module.

Manager

The manager GenServer is optional. Its job is to maintain a list of nodes that will be Node.connect()ed and Node.monitor()ed. If any of those goes down, the manager will periodically (5 seconds) try to reconnect.

Utility Module

The utility module contains functions and macros that allow low-friction node-agnostic pid lookup, call, and cast functionality.

Example Usage

Starting the manager from a module-based supervisor:

defmodule MySupervisor  do
  @moduledoc """
  Supervisor some stuff
  """
  use Supervisor

  def start_link(args), do: Supervisor.start_link(__MODULE__, [args], name: __MODULE__)

  def init([args]) do
    Distributed.register()
    children_list = children()
    Supervisor.init(children_list, [strategy: :one_for_one])
  end

  def children do
    distributed_node_list = [String.to_atom("app1@remote_node1"), String.to_atom("app2@remote_node2")]
    [
      Supervisor.child_spec({Distribunator.Manager, distributed_node_list}, restart: :transient),
    ]
  end
end

A GenServer that is Distribunated

defmodule MyWorker do
  @moduledoc """
  Do some work.
  """
  use GenServer
  require Distributed

  ##############################
  # API
  ##############################

  @doc """
  Do some foo-ing. Calling this API will lookup the first pid registered with
  the MyWorker module and perform a GenServer.call on it, returning the result.
  """
  def foo, do: Distributed.call(:foo)

  def start_link(:ok) do
    GenServer.start_link(__MODULE__, :ok, [name: __MODULE__])
  end

  defmodule State do
    @moduledoc false
    defstruct [
    ]
  end

  ##############################
  # GenServer Callbacks
  ##############################

  @impl true
  def init(:ok) do
    # Register this module and pid with Distribunator so it can be called from anywhere
    Distributed.register()
    {:ok, %State{}}
  end

  @impl true
  def handle_call(:foo, _from, state) do
    {:reply, :ok, state}
  end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/distribunator.