Why is Presence metas a list?

I’m working on a PR to implement Phoenix.Presence.sync_diff in Elixir just like we have Presence.syncDiff in JS. I never really asked if anyone wants this, if it doesn’t get merged I’ll still benefit from understanding it deeper.

I realized that my implementation of sync_diff naively assumes that there is only one element in the metas: [] list and that the joins in the diff I received has more recent versions of the presences than the existing state in the client process. It has worked without issue that way in my very basic tiny-scale LiveView app.

Here’s my implementation which would not pass all the tests for the JS version of the function:

  def sync_diff(state, %{joins: joins, leaves: leaves}) do
    state
    |> Map.drop(Map.keys(leaves))
    |> Map.merge(joins)
  end

This brings me to my question:

Why is metas: [] a list and not just a meta: %{}?

My assumption is that when all the Phoenix.Tracker.Shards get to their eventually consistent state then metas: [] will be a one-element list, but while syncing is happening between shards there could be more than one meta in the list until we determine which the latest one is and remove the others.

I’d really appreciate some more clarity on this.

The metas represent a distinct presence. For any given key (say user_id), there can be multiple presences for that user. For example, you open multiple browser tabs, or you sign in from the desktop and mobile, so metas is only ever a single element list if a user only has one tab/device connected. Make sense?

7 Likes

Thanks for the quick reply @chrismccord, that makes a lot more sense than my assumptions, and settles it!