Implementing distributed user counters

Is there a reason you’re using ETS instead of Redis?

You can use Phoenix Presence and push joins/leaves to Redis directly.

Here’s an example of using Redis to track users and user counts.

SADD/SREM handle adding/removing users to a set, while INCRBY/DECRBY update the count.

def handle_metas(topic, %{joins: joins, leaves: leaves}, _presences, state) do
  key_id    = "#{topic}:users"
  key_count = "#{topic}:count"

  commands =
    Enum.flat_map(joins,  fn {id, _} -> [["SADD", key_id, id], ["INCRBY", key_count, 1]] end) ++
    Enum.flat_map(leaves, fn {id, _} -> [["SREM", key_id, id], ["DECRBY", key_count, 1]] end)

  Task.start(fn -> Redix.pipeline(:redix, commands) end)

  {:ok, state}
end

If you want to assign users to room* topics, you could also use a Redis sorted set. Store room IDs as members and their user counts as scores:

ZADD rooms 65 room1
ZADD rooms 54 room2

You can then use ZRANGE or ZPOPMIN to find a room under the threshold (e.g., < 70) and assign users accordingly.