-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathhighlander.ex
More file actions
76 lines (61 loc) · 1.82 KB
/
Copy pathhighlander.ex
File metadata and controls
76 lines (61 loc) · 1.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
defmodule Highlander do
@external_resource "README.md"
@moduledoc @external_resource
|> File.read!()
|> String.split("<!-- MDOC !-->")
|> Enum.fetch!(1)
use GenServer
require Logger
def child_spec(child_child_spec) do
child_child_spec = Supervisor.child_spec(child_child_spec, [])
Logger.debug("Starting Highlander with #{inspect(child_child_spec.id)} as uniqueness key")
%{
id: child_child_spec.id,
start: {GenServer, :start_link, [__MODULE__, child_child_spec, []]}
}
end
@impl true
def init(child_spec) do
Process.flag(:trap_exit, true)
{:ok, register(%{child_spec: child_spec})}
end
@impl true
def handle_info({:DOWN, ref, :process, _, _}, %{ref: ref} = state) do
{:noreply, register(state)}
end
def handle_info({:EXIT, _pid, :name_conflict}, %{pid: pid} = state) do
:ok = Supervisor.stop(pid, :shutdown)
{:stop, {:shutdown, :name_conflict}, Map.delete(state, :pid)}
end
@impl true
def terminate(reason, %{pid: pid}) do
:ok = Supervisor.stop(pid, reason)
end
def terminate(_, _), do: nil
defp name(%{child_spec: %{id: global_name}}) do
{__MODULE__, global_name}
end
defp handle_conflict(_name, pid1, pid2) do
Process.exit(pid2, :name_conflict)
pid1
end
defp register(state) do
case :global.register_name(name(state), self(), &handle_conflict/3) do
:yes -> start(state)
:no -> monitor(state)
end
end
defp start(state) do
{:ok, pid} = Supervisor.start_link([state.child_spec], strategy: :one_for_one)
Map.put(state, :pid, pid)
end
defp monitor(state) do
case :global.whereis_name(name(state)) do
:undefined ->
register(state)
pid ->
ref = Process.monitor(pid)
%{child_spec: state.child_spec, ref: ref}
end
end
end