Last active
August 29, 2015 14:20
-
-
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!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.