I am struggling whole day on this question. Current Monitor stores groups referenced by user_id, the question is how to store data in GenServer to handle many users related to many groups, finally to map groups and return users count by given group name?
Groups will be replaced frequently on each Phoenix Channel call.
My current code:
defmodule Myapp.Monitor do
use GenServer
def create(user_id) do
case GenServer.whereis(ref(user_id)) do
nil -> Myapp.Supervisor.start_child(user_id)
end
end
def start_link(user_id) do
GenServer.start_link(__MODULE__, [], name: ref(user_id))
end
def set_groups(user_pid, groups) do
try_call user_pid, {:set_groups, groups}
end
def handle_call({:set_groups, groups}, _from, state) do
{ :reply, groups, groups } # reset user groups on each set_group call.
end
defp ref(user_id) do
{:global, {:user, user_id}}
end
defp try_call(user_id, call_function) do
case GenServer.whereis(ref(user_id)) do
nil -> {:error, :invalid_user}
user_pid -> GenServer.call(user_pid, call_function)
end
end
end
Supervisor:
defmodule Myapp.Supervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, :ok, name: __MODULE__)
end
def start_child(user_id) do
Supervisor.start_child(__MODULE__, [user_id])
end
def init(:ok) do
supervise([worker(Myapp.Monitor, [], restart: :temporary)], strategy: :simple_one_for_one)
end
end
Usage:
Monitor.create(5)
Monitor.set_groups(5, ['a', 'b', 'c'])
Monitor.create(6)
Monitor.set_groups(6, ['a', 'b'])
Monitor.set_groups(6, ['a', 'c'])
# not implemented:
# Monitor.users_in_gorup('a') # -> 2
# Monitor.users_in_gorup('b') # -> 1
# Monitor.users_in_gorup('c') # -> 2