Presence 没有接听用户离开事件?

Presence not picking up user leave events?

我需要在用户离开频道时执行一些操作(大多数情况下他们是自愿关闭标签页,但也可能存在连接loss/timeout等)

根据 https://elixirforum.com/t/phoenix-presence-run-some-code-when-user-leaves-the-channel/17739 and 之类的帖子,拦截来自 Presence"presence_diff" 事件似乎是一种万无一失的方法,因为它还应该涵盖连接异常终止的情况.

奇怪的是,presence_diff事件似乎只在我通过Presence.track跟踪用户时触发,而不是在用户离开时触发。

同时,在我的频道中添加 terminate(reason, socket) 回调可以正确捕获离开事件。

我想知道我的配置有什么问题。还是我没有正确理解 Presence 的用法?

示例代码:

def join("participant:" <> participant_id, _payload, socket) do
  if socket.assigns.participant_id == participant_id do
    send(self(), :after_participant_join)
    {:ok, socket}
  else
    {:error, %{reason: "unauthorized"}}
  end
end

def handle_info(:after_participant_join, socket) do
  experiment_id = socket.assigns.experiment_id

  Presence.track(socket, experiment_id, %{
    # keys to track
  })

  # Broadcast something
  # broadcast(socket, ...)

  {:noreply, socket}
end

intercept(["presence_diff"])

def handle_out("presence_diff", payload, socket) do
  # Only gets triggered at Presence.track, but not when the connection is closed.
  IO.puts("presence_diff triggered, payload is #{inspect(payload)}")

  leaves = payload.leaves

  for {experiment_id, meta} <- leaves do
    IO.puts("Leave information: #{meta}")

    # Do stuffs
    end
end

# This works, however.
def terminate(reason, socket) do
  IO.puts("terminated. #{inspect(reason)}")

  # Do stuffs.
end

好的,我想我知道发生了什么:正如其名称所示,每个 "participant:" <> participant_id 主题仅由一名参与者订阅。因此,当该参与者退出时,该进程也会终止,并且没有人能够对 presence_diff 消息采取行动。

仍然需要一个单独的过程。可以从该进程调用 MyApp.Endpoint.subscribe 以订阅 "participant:" <> participant_id 主题并对 presence_diff 消息采取行动。

或者可以设置外接显示器。参见