Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for automatic cluster formation #62

Open
ckreiling opened this issue Jul 24, 2021 · 0 comments
Open

Support for automatic cluster formation #62

ckreiling opened this issue Jul 24, 2021 · 0 comments

Comments

@ckreiling
Copy link

ckreiling commented Jul 24, 2021

Horde has the helpful NodeListener genserver that I've been copy-pasting into toy projects where I'm playing with DeltaCrdt. My approach to libraries built on top of DeltaCrdt has been to start the DeltaCrdt process under a supervisor, with a downstream child that bootstraps node membership. It'd be nice to have an optional NodeListener baked into DeltaCrdt - or even a setup like mine that use a supervisor.

Here's a ReplicatedMap implementation I came up with:

defmodule ReplicatedMap do
  use Supervisor

  alias ReplicatedMap.{NodeWatcher}

  def start_link(opts) do
    opts = Keyword.put_new(opts, :name, __MODULE__)
    Supervisor.start_link(__MODULE__, opts, name: :"#{opts[:name]}.Supervisor")
  end

  def init(opts) do
    name = opts[:name]
    members = opts[:members] || :auto

    children = [
      {DeltaCrdt, [name: name, crdt: DeltaCrdt.AWLWWMap]},
      with_members(members, name)
    ]

    # Restart the node watcher when the ReplicatedMap crashes
    # so that node membership is properly resync'd w/ the DeltaCrdt.
    Supervisor.init(children, strategy: :rest_for_one)
  end

  @spec set_members(map :: module(), members :: [GenServer.server()])
  def set_members(map, members) when is_list(members) do
    DeltaCrdt.set_neighbours(map, members)
  end

  @spec put(map :: module(), key :: any(), value :: any()) :: module()
  def put(map \\ __MODULE__, key, value) do
    DeltaCrdt.put(map, key, value)
  end

  @spec delete(map :: module(), key :: any()) :: module()
  def delete(map \\ __MODULE__, key) do
    DeltaCrdt.delete(map, key)
  end

  @spec drop(map :: module(), keys :: [any()]) :: module()
  def drop(map \\ __MODULE__, keys) when is_list(keys) do
    DeltaCrdt.drop(map, keys)
  end

  @spec get(map :: module(), key :: any()) :: nil | any()
  def get(map \\ __MODULE__, key) do
    case DeltaCrdt.read(map, [key]) do
      %{^key => val} -> val
      _ -> nil
    end
  end

  defp with_members(:auto, crdt_name) do
    {NodeWatcher, [name: :"#{crdt_name}.NodeWatcher", crdt_name: crdt_name]}
  end

  defp with_members(members, crdt_name) when is_list(members) do
    {Task, fn -> DeltaCrdt.set_neighbours(crdt_name, members) end}
  end
end

This library has been so fun to play with, and I use it to show off "the power of Elixir/Erlang" whenever I have the chance.

@ckreiling ckreiling changed the title Automatic cluster formation Support for automatic cluster formation Jul 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant