Presence.update without a socket?

I need to update some presence information outside of the channel portion of my code. As a contrived example let’s say each user’s presence info contains their membership level for others to see and envy at. Some event in the system upgrades their membership (maybe a purchase, maybe an Admin grants it, etc) and I need that to update their presence info and be pushed to users as a presence update.

I can’t use Presence.update/3 because that requires a socket. Presence.update/4 looks promising, but the first argument is a pid and I have no idea what pid that should be or how to find it. Is this even possible?

Maybe send a message to the channel process, and in handle_info call Presence.update. To find the pid, register the process with Registry or something similar. Then look it up there …

1 Like

Found a solution. The above answer is essentially correct, but Phoenix PubSub has it largely built in so you don’t have to mess pids and Registry yourself.

In your channel’s join event(s) do something like:

MyAppWeb.Endpoint.subscribe("presence:" <> socket.assigns.user_id)

Then add a handle_info func to your channel. In this case something like:

def handle_info(%{topic: "presence:" <> _, event: "update", payload: meta}, socket) do
  MyAppWeb.Presence.update(socket, socket.assigns.user_id, meta)
  {:noreply, socket}

Elsewhere in your app call MyAppWeb.Endpoint.broadcast("presence:#{user_id}", "update", %{...}) and it will be handled by the above function in the correct channel process.