Skip to content

Instantly share code, notes, and snippets.

@ray-sh
Last active July 19, 2017 14:48
Show Gist options
  • Save ray-sh/3d2a360a08877e6ddb175a0ffb528ecd to your computer and use it in GitHub Desktop.
Save ray-sh/3d2a360a08877e6ddb175a0ffb528ecd to your computer and use it in GitHub Desktop.
Elixir process register
Requirements
1>Two kinds of GenServer
2>The GenServer will share same process registry module
3>The Registry module's is used to keep the name/pip mapping with the process, so the client will talk with the Registry directly
to get correspoding PID by name. The Registry should monitor the process and keep the name/pid map up-to-date all the time.
How the following work?
1>The My.Registry must implement register_name/unregister_name/whereis_name/send
2>The client start_link function must use name: {:via, Registry, name} since the Registry will keep different kind of process,
we usually use tuple {:server,name} to distinguish
3>The server's client method also use {:via, Registry, name} to retrive the pid from Registry
defmodule My.Registry do
@moduledoc false
use GenServer
def start do
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
end
def register_name(name,pid) do
GenServer.call(__MODULE__,{:reg,name,pid})
end
def unregister_name(name) do
GenServer.cast(__MODULE__,{:unreg,name})
end
def whereis_name(name) do
GenServer.call(__MODULE__,{:where,name})
end
def send(name,msg) do
Kernel.send(whereis_name(name),msg)
end
def handle_call({:reg,name,pid}, _from, state) do
case Map.get(state,name) do
nil ->
Process.monitor(pid)
{:reply, :yes, Map.put(state,name,pid)}
_ ->
{:reply,:no,state}
end
end
def handle_call({:where,name}, _from, state) do
{:reply,Map.get(state,name,:undefined),state}
end
def handle_cast({:unreg,name}, state) do
{:noreply, Map.delete(state,name)}
end
end
defmodule Server do
use GenServer
def start_link(name) do
GenServer.start_link(__MODULE__,nil, name: {:via,My.Registry,{:server,name}})
end
def myname(name) do
GenServer.call({:via, My.Registry,{:server,name}},name)
end
def handle_call(name,_from,state) do
{:reply,name,state}
end
end
defmodule Database do
use GenServer
def start_link(name), do: GenServer.start_link(__MODULE__,nil,{:via,My
.Registry,{:database,name}})
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment