Horde.Registry behaviour (Horde v0.8.6) View Source

A distributed process registry.

Horde.Registry implements a distributed Registry backed by a δ-CRDT (provided by DeltaCrdt). This CRDT is used for both tracking membership of the cluster and implementing the registry functionality itself. Local changes to the registry will automatically be synced to other nodes in the cluster.

Cluster membership is managed with Horde.Cluster. Joining a cluster can be done with Horde.Cluster.set_members/2. To take a node out of the cluster, call Horde.Cluster.set_members/2 without that node in the list. Alternatively, setting the members startup option to :auto will make Horde auto-manage cluster membership so that all (and only) visible nodes are members of the cluster.

Horde.Registry supports the common "via tuple", described in the documentation for GenServer.

Horde.Registry is API-compatible with Registry, with the following exceptions:

  • Horde.Registry does not support keys: :duplicate.
  • Horde.Registry does not support partitions.
  • Horde.Registry sends an exit signal to a process when it has lost a naming conflict. See Horde.Registry.register/3 for details.

Module-based Registry

Horde supports module-based registries to enable dynamic runtime configuration.

defmodule MyRegistry do
  use Horde.Registry

  def start_link(_) do
    Horde.Registry.start_link(__MODULE__, [keys: :unique], name: __MODULE__)
  end

  def init(init_arg) do
    [members: members()]
    |> Keyword.merge(init_arg)
    |> Horde.Registry.init()
  end

  defp members() do
    [Node.self() | Node.list()]
    |> Enum.map(fn node -> {__MODULE__, node} end)
  end
end

Then you can use MyRegistry.child_spec/1 and MyRegistry.start_link/1 in the same way as you'd use Horde.Registry.child_spec/1 and Horde.Registry.start_link/1.

Link to this section Summary

Link to this section Types

Specs

option() ::
  {:keys, :unique}
  | {:name, atom()}
  | {:delta_crdt_options, [DeltaCrdt.crdt_option()]}
  | {:members, [Horde.Cluster.member()] | :auto}

Specs

options() :: [option()]

Link to this section Callbacks

Specs

child_spec(options :: options()) :: Supervisor.child_spec()

Specs

init(options :: Keyword.t()) :: {:ok, options()} | :ignore

Link to this section Functions

See start_link/2 for options.

Specs

count(registry :: Registry.registry()) :: non_neg_integer()

See Registry.count/1.

Link to this function

count_match(registry, key, pattern, guards \\ [])

View Source

See Registry.count_match/4.

Link to this function

delete_meta(registry, name)

View Source

Specs

delete_meta(registry :: Registry.registry(), name :: Registry.key()) :: :ok

See Registry.delete_meta/2.

Link to this function

dispatch(registry, key, mfa_or_fun, opts \\ [])

View Source

See Registry.dispatch/4.

Works like Registry.init/1.

Specs

keys(registry :: Registry.registry(), pid()) :: [Registry.key()]

See Registry.keys/2.

See Registry.lookup/2.

Link to this function

match(registry, key, pattern, guards \\ [])

View Source

See Registry.match/4.

Specs

meta(registry :: Registry.registry(), key :: Registry.meta_key()) ::
  {:ok, Registry.meta_value()} | :error

See Registry.meta/2.

Link to this function

put_meta(registry, key, value)

View Source

Specs

put_meta(
  registry :: Registry.registry(),
  key :: Registry.meta_key(),
  value :: Registry.meta_value()
) :: :ok

See Registry.put_meta/3.

Link to this function

register(registry, name, value)

View Source

Specs

register(
  registry :: Registry.registry(),
  name :: Registry.key(),
  value :: Registry.value()
) :: {:ok, pid()} | {:error, {:already_registered, pid()}}

Register a process under the given name. See Registry.register/3.

When 2 clustered registries register the same name at exactly the same time, it will seem like name registration succeeds for both registries. The function returns {:ok, pid} for both of these calls.

However, due to the eventually consistent nature of the CRDT, conflict resolution will take place, and the CRDT will pick one of the two processes as the "winner" of the name. The losing process will be sent an exit signal (using Process.exit/2) with the following reason:

{:name_conflict, {name, value}, registry_name, winning_pid}

When two registries are joined using Horde.Cluster.set_members/2, this name conflict message can also occur.

When a cluster is recovering from a netsplit, this name conflict message can also occur.

See Registry.select/2.

See Registry.start_link/1.

Does not accept [partitions: x], nor [keys: :duplicate] as options.

Link to this function

start_link(mod, init_arg, opts \\ [])

View Source
Link to this function

stop(supervisor, reason \\ :normal, timeout \\ 5000)

View Source

Specs

stop(Supervisor.supervisor(), reason :: term(), timeout()) :: :ok
Link to this function

unregister(registry, name)

View Source

Specs

unregister(registry :: Registry.registry(), name :: Registry.key()) :: :ok

See Registry.unregister/2.

Link to this function

unregister_match(registry, key, pattern, guards \\ [])

View Source

See Registry.unregister_match/4.

Link to this function

update_value(registry, key, callback)

View Source

See Registry.update_value/3.