Packages
finitomata
0.32.0
0.41.0
0.40.0
0.35.0
0.34.0
0.33.0
0.32.0
0.31.1
0.30.3
0.30.2
0.30.1
0.30.0
0.29.10
0.29.9
0.29.8
0.29.7
0.29.6
0.29.5
0.29.4
0.29.3
0.29.2
0.29.1
0.29.0
0.28.1
0.28.0
0.27.1
0.27.0
0.26.4
0.26.3
0.26.2
0.26.1
0.26.0
0.25.0
0.24.4
0.24.3
0.24.2
0.24.1
0.24.0
0.23.7
0.23.6
0.23.5
0.23.4
0.23.3
0.23.2
0.23.1
0.23.0
0.22.1
0.22.0
0.21.4
0.21.3
0.21.2
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.1
0.17.0
0.16.0
0.15.1
0.15.0
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.1
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.1
0.1.0
The FSM implementation generated from PlantUML textual representation.
Current section
Files
Jump to
Current section
Files
lib/finitomata/distributed/group_monitor.ex
major = System.otp_release()
otp_version =
try do
{:ok, contents} = File.read(Path.join([:code.root_dir(), "releases", major, "OTP_VERSION"]))
String.split(contents, "\n", trim: true)
else
[full] -> full
_ -> major
catch
:error, _ -> major
end
|> String.split(".")
|> case do
[major] -> [major, 0, 0]
[major, minor] -> [major, minor, 0]
[major, minor, patch | _] -> [major, minor, patch]
end
|> Enum.join(".")
if Version.compare(otp_version, "25.1.0") == :lt do
defmodule Finitomata.Distributed.GroupMonitor do
@moduledoc false
use GenServer
alias Finitomata.Distributed.Supervisor, as: Sup
@update_interval Application.compile_env(:finitomata, :pg_update_interval, 500)
def start_link(id) do
GenServer.start_link(__MODULE__, id, name: sup_name(id))
end
def count(id), do: GenServer.call(sup_name(id), :count)
def members(id), do: id |> Sup.group() |> :pg.get_members()
defp sup_name(id), do: Module.concat(id, "GroupMonitor")
@impl GenServer
def init(id) do
Process.send_after(self(), {:update, id}, @update_interval)
{:ok, {0, MapSet.new([])}}
end
@impl GenServer
def handle_info({:update, id}, {count, members}) do
updated_members = id |> Sup.group() |> :pg.get_members() |> MapSet.new()
joined = MapSet.difference(updated_members, members)
handle_join(id, joined)
left = MapSet.difference(members, updated_members)
handle_leave(id, left)
Process.send_after(self(), {:update, id}, @update_interval)
{:noreply, {count, updated_members}}
end
defp handle_join(id, pids) do
for pid <- pids do
name = GenServer.call(pid, :name)
Sup.put(id, name, %{node: :erlang.node(pid), pid: pid, ref: make_ref()})
end
end
defp handle_leave(id, pids) do
Sup.delete_by_pids(id, pids)
end
@impl GenServer
def handle_call(:count, _from, {count, members}), do: {:reply, count, {count, members}}
end
else
defmodule Finitomata.Distributed.GroupMonitor do
@moduledoc false
use GenServer
alias Finitomata.Distributed.Supervisor, as: Sup
def start_link(id) do
GenServer.start_link(__MODULE__, id, name: sup_name(id))
end
def count(id), do: GenServer.call(sup_name(id), :count)
def members(id), do: id |> Sup.group() |> :pg.get_members()
defp sup_name(id), do: Module.concat(id, "GroupMonitor")
@impl GenServer
def init(id) do
{_reference, _pids} =
id
|> Sup.group()
|> :pg.monitor()
{:ok, 0}
end
@impl GenServer
def handle_info({ref, :join, group, pids}, count) do
{:noreply,
Enum.reduce(pids, count, fn pid, counter ->
id = Sup.ungroup(group)
name = GenServer.call(pid, :name)
Sup.put(id, name, %{node: :erlang.node(pid), pid: pid, ref: ref})
counter + 1
end)}
end
@impl GenServer
def handle_info({_ref, :leave, group, pids}, count) do
deleted =
group
|> Sup.ungroup()
|> Sup.delete_by_pids(pids)
|> map_size()
{:noreply, count - deleted}
end
@impl GenServer
def handle_call(:count, _from, count), do: {:reply, count, count}
end
end