Presence.update loop works once then returns {:error, :nopresence}

phoenix
presence
#1

Hello all!

I have a function to loop through each presence and update the same key. It works on the first run but then returns {:error, :nopresence} on each subsequent one.

Been banging my head on this one. If anyone has any ideas I would greatly appreciate it!

def update_presence_for_each(key) do
    for presence <- Presence.list_presences(@topic) do
      Presence.update_presence(self(), @topic, presence.user_id, key)
    end
  end

That function calls the below:

  def update_presence(pid, topic, key, payload) do
    metas =
      Presence.get_by_key(topic, key)[:metas]
      |> List.first()
      |> Map.merge(payload)
    Presence.update(pid, topic, key, metas)
  end

  def list_presences(topic) do
    Presence.list(topic)
    |> Enum.map(fn {_user_id, data} ->
      data[:metas]
      |> List.first()
    end)
  end

All the right values are being passed each time in the loop, so I’m not sure what it could be.

1 Like
#2

I’ve been doing some digging today and think I discovered what may be causing the problem.

I’ve included a ton of IO.puts so you can see what’s happening.

When I inspect the metas before the update that succeeds, notice it has both phx_ref and phx_ref_prev metas. But on the one that fails, it doesn’t have the phx_ref_prev meta.

I’ve confirmed this pattern happens for every update that fails, even if that update runs first in the loop.

I don’t have the right answer yet but am getting closer and will update you all when I figure it out. I’m assuming there’s an issue with my update_presence function that compiles the metas.

1 Like
#3

OK, I figured it out. Pretty simple in retrospect, here’s what happened:

I am looping through all presences in a single user’s process, calling the update and passing these variables (self(), @topic, user_id, key)

The loop fails because you can’t update a users presence metas by passing the other user’s PID, aka the self() part.

By updating the Presence metas of each user in that user’s own process and passing that user’s PID I was able to get it to work.

2 Likes