How to create many GenServer processes from List and map data stored in them?
<p>In both approaches I stuck on How to map processes by given set of ids or groups and then map stored struct to filter data.</p>
<h3><code>%{group =&gt; [users]}</code> implementation.</h3>
<p>I realized that groups will be limited in opposite to users, so I've created one process module that uses groups names as keys.</p>
<p>I'm afraid that in future there will be to many users in few groups, so my question is how can I split current <code>UserGroupServer</code> module to keep many separated processes identified by group names? I would like to keep functionality of current module, within init processes by groups list, additionally I don't know how to map each process to get groups by user_id?</p>
<p>Currently I start only one process in Phoenix <code>lib/myapp.ex</code> by including module in children tree list, so I can call <code>UserGroupServer</code> in Channels directly.</p>
<pre><code>defmodule UserGroupServer do
  use GenServer

  ## Client API
  def start_link(opts \\ []) do
   GenServer.start_link(__MODULE__, :ok, opts)
  end

  def update_user_groups_state(server, data) do
    {groups, user_id} = data
    GenServer.call(server, {:clean_groups, user_id}, :infinity)
    users = Enum.map(groups, fn(group) -&gt;
      GenServer.call(server, {:add_user_group, group, user_id}, :infinity)
    end)
    Enum.count(Enum.uniq(List.flatten(users)))
  end

  def get_user_groups(server, user_id) do
    GenServer.call(server, {:get_user_groups, user_id})
  end

  def users_count_in_gorup(server, group) do
    GenServer.call(server, {:users_count_in_gorup, group})
  end

  ## Callbacks (Server API)

  def init(_) do
    {:ok, Map.new}
  end

  def handle_call({:clean_groups, user_id}, _from, user_group_dict) do
    user_group_dict = user_group_dict
    |&gt; Enum.map(fn({gr, users}) -&gt; {gr, List.delete(users, user_id)} end)
    |&gt; Enum.into(%{})
    {:reply, user_group_dict, user_group_dict}
  end

  def handle_call({:add_user_group, group, user_id}, _from, user_group_dict) do
    user_group_dict = if Map.has_key?(user_group_dict, group) do
      Map.update!(user_group_dict, group, fn(users) -&gt; [user_id | users] end)
    else
      Map.put(user_group_dict, group, [user_id])
    end
    {:reply, Map.fetch(user_group_dict, group), user_group_dict}
  end
end
</code></pre>
<p>test:</p>
<pre><code>defmodule MyappUserGroupServerTest do
  use ExUnit.Case, async: false

  setup do
    {:ok, server_pid} = UserGroupServer.start_link
    {:ok, server_pid: server_pid}
  end

  test &quot;add users&quot;, context do
    c1 = UserGroupServer.update_user_groups_state(context[:server_pid], {[:a, :b, :c], 1})
    assert(1 == c1)
    c2 = UserGroupServer.update_user_groups_state(context[:server_pid], {[:c, :d], 2})
    assert(2 == c2)
    c3 = UserGroupServer.update_user_groups_state(context[:server_pid], {[:x], 2})
    assert(1 == c3)
    c4 = UserGroupServer.update_user_groups_state(context[:server_pid], {[:d], 1})
    assert(1 == c4)
    c5 = UserGroupServer.update_user_groups_state(context[:server_pid], {[:d, :c], 2})
    assert(2 == c5)
  end
end
</code></pre>
<h3>Old approach <code>%{user =&gt; [groups]}</code></h3>
<p>Monitor stores groups list assigned to user_id. How to find users that are in given group? Have I to create separate processes that will handle m..n relation between groups and user ids? What should I change to get each user groups and then Map them?</p>
<p>Server implementation:</p>
<pre><code>defmodule Myapp.Monitor do
  use GenServer

  def create(user_id) do
    case GenServer.whereis(ref(user_id)) do
      nil -&gt; 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 -&gt; {:error, :invalid_user}
      user_pid -&gt; GenServer.call(user_pid, call_function)
    end
  end
end
</code></pre>
<p>Supervisor:</p>
<pre><code>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
</code></pre>
<p>Example:</p>
<pre><code>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'])

# Monitor.users_in_gorup('a') # -&gt; 2
# Monitor.users_in_gorup('b') # -&gt; 1
# Monitor.users_in_gorup('c') # -&gt; 2

# or eventually more desired:
# Monitor.unique_users_in_groups(['a', 'b', 'c']) # -&gt; 2
# or return in set_groups unique_users_in_groups result
</code></pre>