Thanks @codeanpeace and @imkleats for your suggestions, they really helped me 
I’m still working out the details, but the path I’m moving forward with, is implementing a custom tracker.
defmodule MyTracker do
def handle_diff(diff, state) do
state =
if Map.has_key?(state, :leave_tasks),
do: state,
else: Map.put(state, :leave_tasks, %{})
state =
Enum.reduce(diff, state, fn {topic, {joins, leaves}}, state ->
state =
Enum.reduce(joins, state, fn {user_id, meta}, state ->
{task, state} = pop_in(state.leave_tasks, [user_id])
if is_nil(task) do
event = %Events.UserJoined{user_data: meta}
PubSub.pub(topic, event)
else
Log.info("Kill leave task for user_id: #{user_id}")
Task.shutdown(task, :brutal_kill)
end
state
end)
Enum.reduce(leaves, state, fn {user_id, meta}, state ->
event = %Events.UserLeft{user_data: meta}
if root_presence() do # I have more than one scope of presence. True means is "root" presence.
task = Task.async(fn -> broadcast_user_left(topic, event) end)
put_in(state, [:leave_tasks, user_id], task)
else
broadcast_user_left(topic, event)
state
end
end)
end)
{:ok, state}
end
def broadcast_user_left(topic, event) do
Process.sleep(3000)
PubSub.pub(topic, event)
end
end
This is solving the flickering issue, but it added a new one I’m too tired to tackle today: When you try to move out of a live view and you have any pending leave tasks, the user needs to wait for the task to run (in this case 3 seconds :P).
I need to somehow capture LiveView’s shutdown event and send that to the tracker. Is that possible? A “before_shutdown” hook?