Skip to content

Instantly share code, notes, and snippets.

@qcam
Created September 9, 2018 09:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qcam/82eb5ae32e003b1911efdd51a311ceda to your computer and use it in GitHub Desktop.
Save qcam/82eb5ae32e003b1911efdd51a311ceda to your computer and use it in GitHub Desktop.
defmodule GCounter.Node do
use GenServer
def start_link(node_name) do
GenServer.start_link(__MODULE__, node_name, [name: node_name])
end
@impl true
def init(node_name) do
init_counter = %{node_name => 0}
{:ok, {node_name, init_counter}}
end
@impl true
def handle_cast(:increment, {node_name, counter}) do
counter = Map.update!(counter, node_name, &(&1 + 1))
{:noreply, {node_name, counter}}
end
@impl true
def handle_cast({:merge, remote_counter}, {local_node_name, local_counter}) do
local_counter =
Enum.reduce(remote_counter, local_counter, fn {node_name, count}, local_counter ->
Map.update(local_counter, node_name, 0, &max(&1, count))
end)
{:noreply, {local_node_name, local_counter}}
end
@impl true
def handle_call(:count, _from, {_, counter} = state) do
count = Enum.reduce(counter, 0, fn {_, count}, total -> total + count end)
{:reply, count, state}
end
# TODO: Make these configurable.
@remote_nodes [:node1, :node2, :node3]
@impl true
def handle_info(:gossip, {node_name, counter}) do
Enum.each(@remote_nodes, &GenServer.cast(&1, {:merge, counter}))
{:noreply, {node_name, counter}}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment