Skip to content

Instantly share code, notes, and snippets.

@jarsen
Last active August 29, 2015 14:20
Show Gist options
  • Save jarsen/1f413220a43de31b998b to your computer and use it in GitHub Desktop.
Save jarsen/1f413220a43de31b998b to your computer and use it in GitHub Desktop.
run TickerNode.start in multiple linked nodes and they link together and count!
import :timer, only: [sleep: 1]
defmodule TickerNode do
@interval 2000 # 2 seconds
@name :ticker
def start do
pid = spawn(__MODULE__, :run, [nil, nil])
if :global.whereis_name(@name) == :undefined do
IO.puts "Spawning as root node"
register_root(pid)
send pid, {:tick, 0}
else
IO.puts "Spawning node"
register_client(pid)
end
pid
end
defp register_root(pid) do
:global.register_name(@name, pid)
end
defp register_client(client_pid) do
send :global.whereis_name(@name), { :register, client_pid }
end
def run(prev, next) do
receive do
{ :register, pid } ->
# Add pid to the end of the linked list
IO.puts "registering #{inspect pid}"
if prev == nil do # base case - only 1 item in list
send pid, {:prev, self}
send pid, {:next, self}
run pid, pid
else
send prev, {:next, pid}
send pid, {:prev, prev}
send pid, {:next, self}
run pid, next
end
{ :prev, new_prev } ->
run new_prev, next
{ :next, new_next } ->
run prev, new_next
{ :tick, new_val } ->
sleep @interval
IO.puts "Value: #{new_val}"
send next || self, {:tick, new_val + 1}
run prev || self, next || self
end
end
end
@rob-brown
Copy link

By convention start returns {:ok, pid} on success.
I would separate the client and server into two modules.
The linked-list approach is clever, but in practice it's difficult to debug. I would just use a list of pids and an index. This will also simplify your logic.
Since the timer is just used in one place, I would skip the import and use :timer.sleep @interval directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment