全书目录

第三十八篇:Phoenix 完全指南 —— 实时频道城邦宇宙

第十七章:PubSub,是全城广播网;Presence,是在线名册处

1 分钟 338 字 第 736 / 962 个阅读单元

这两个概念经常连着出现,但职责不同。

#PubSub:广播网

Phoenix.PubSub 负责:

  • 订阅主题
  • 广播消息
  • 跨节点扩散

最小用法非常直接:

elixir
children = [
  {Phoenix.PubSub, name: City.PubSub}
]
elixir
Phoenix.PubSub.subscribe(City.PubSub, "org:7:dispatches")
Phoenix.PubSub.broadcast(City.PubSub, "org:7:dispatches", {:dispatch_created, dispatch})

这意味着:

  • Context 可以广播
  • LiveView 可以订阅
  • Channel 可以订阅
  • 其他普通进程也可以订阅

PubSub 是 Phoenix 城邦里最重要的“松耦合交通层”。

#Presence:在线名册

Presence 不是“聊天室专属功能”,本质上是:

跟踪谁在某个 topic 上在线,以及 join/leave diff。

定义 Presence 模块:

elixir
defmodule CityWeb.Presence do
  use Phoenix.Presence,
    otp_app: :city,
    pubsub_server: City.PubSub
end

在 Channel 里追踪:

elixir
def join("district:" <> district_id, _payload, socket) do
  send(self(), :after_join)
  {:ok, assign(socket, :district_id, district_id)}
end

def handle_info(:after_join, socket) do
  topic = "district:#{socket.assigns.district_id}"

  {:ok, _} =
    CityWeb.Presence.track(
      socket,
      socket.assigns.current_user.id,
      %{online_at: System.system_time(:second)}
    )

  push(socket, "presence_state", CityWeb.Presence.list(topic))
  {:noreply, socket}
end

客户端还能用官方 JS Presence helper 同步状态。

你可以把它想成:

text
PubSub = 城市广播喇叭
Presence = 进出登记簿

一个负责“通知”,一个负责“谁在场”。