Skip to content

Instantly share code, notes, and snippets.

@rubysolo
Last active December 26, 2015 02:09
Show Gist options
  • Save rubysolo/7075970 to your computer and use it in GitHub Desktop.
Save rubysolo/7075970 to your computer and use it in GitHub Desktop.
Ring of message passing processes in Elixir (see http://benjamintanweihao.github.io/blog/2013/10/09/elixir-by-example-ring/)
defmodule Ring do
def run(member_count, loop_count, message) do
log(:ringleader, "building ring with #{ member_count - 1 } more nodes...")
next_pid = spawn_link(__MODULE__, :build_ring, [member_count - 2, self])
log(:ringleader, "sending initial message to #{ inspect(next_pid) }...")
next_pid <- {:message, message, loop_count}
message_loop(next_pid)
end
def message_loop(next_pid) do
receive do
{:message, message, 0} ->
log(:ringleader, "got last message: #{ message }; terminating...")
:ok
{:message, message, m} ->
log(:ringleader, "got message: #{ message }; forwarding to #{ inspect(next_pid) }; #{ m - 1 } loops to go...")
next_pid <- {:message, message, m - 1}
message_loop(next_pid)
end
end
def relay(next_pid) do
receive do
{:message, message, m} ->
log(:node, "got message: #{ message }; forwarding to #{ inspect(next_pid) }")
next_pid <- {:message, message, m}
if m > 0, do: relay(next_pid)
end
:ok
end
def build_ring(0, ringleader_pid) do
log(:final, "ring is complete; connecting back to ringleader (#{ inspect(ringleader_pid) })")
relay(ringleader_pid)
end
def build_ring(remaining, ringleader_pid) do
log(:node, "extending ring; #{ remaining } more nodes to go...")
next = spawn_link(__MODULE__, :build_ring, [remaining - 1, ringleader_pid])
relay(next)
end
def log(role, message) do
IO.puts "[#{ inspect(self) }][#{ role }] #{ message }"
end
end
iex(1)> Ring.run 5, 3, "hello"
[#PID<0.41.0>][ringleader] building ring with 4 more nodes...
[#PID<0.41.0>][ringleader] sending initial message to #PID<0.44.0>...
[#PID<0.44.0>][node] extending ring; 3 more nodes to go...
[#PID<0.44.0>][node] got message: hello; forwarding to #PID<0.45.0>
[#PID<0.45.0>][node] extending ring; 2 more nodes to go...
[#PID<0.45.0>][node] got message: hello; forwarding to #PID<0.46.0>
[#PID<0.46.0>][node] extending ring; 1 more nodes to go...
[#PID<0.46.0>][node] got message: hello; forwarding to #PID<0.47.0>
[#PID<0.47.0>][final] ring is complete; connecting back to ringleader (#PID<0.41.0>)
[#PID<0.47.0>][node] got message: hello; forwarding to #PID<0.41.0>
[#PID<0.41.0>][ringleader] got message: hello; forwarding to #PID<0.44.0>; 2 loops to go...
[#PID<0.44.0>][node] got message: hello; forwarding to #PID<0.45.0>
[#PID<0.45.0>][node] got message: hello; forwarding to #PID<0.46.0>
[#PID<0.46.0>][node] got message: hello; forwarding to #PID<0.47.0>
[#PID<0.47.0>][node] got message: hello; forwarding to #PID<0.41.0>
[#PID<0.41.0>][ringleader] got message: hello; forwarding to #PID<0.44.0>; 1 loops to go...
[#PID<0.44.0>][node] got message: hello; forwarding to #PID<0.45.0>
[#PID<0.45.0>][node] got message: hello; forwarding to #PID<0.46.0>
[#PID<0.46.0>][node] got message: hello; forwarding to #PID<0.47.0>
[#PID<0.47.0>][node] got message: hello; forwarding to #PID<0.41.0>
[#PID<0.41.0>][ringleader] got message: hello; forwarding to #PID<0.44.0>; 0 loops to go...
[#PID<0.44.0>][node] got message: hello; forwarding to #PID<0.45.0>
[#PID<0.45.0>][node] got message: hello; forwarding to #PID<0.46.0>
[#PID<0.46.0>][node] got message: hello; forwarding to #PID<0.47.0>
[#PID<0.47.0>][node] got message: hello; forwarding to #PID<0.41.0>
[#PID<0.41.0>][ringleader] got last message: hello; terminating...
:ok
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment