Phoenix PubSub shout事件重复触发问题咨询
解决Phoenix频道shout事件多次触发的问题
问题根源
你的代码逻辑存在重复推送问题:
- 每个客户端连接到
world:lobby频道时,都会订阅zone_1PubSub话题 - 当任意客户端发送
shout消息,handle_in会通过PubSub把消息广播给所有订阅zone_1的客户端进程 - 每个客户端进程的
handle_info收到消息后,又执行broadcast(socket, "shout", ...),将消息再次广播到整个world:lobby频道 - 最终每个客户端会收到N次消息(N等于当前连接的客户端总数),导致
shout事件多次触发
解决方案
你不需要在handle_info里广播到频道,而是直接把PubSub收到的消息推送给当前客户端即可。因为PubSub已经把消息分发到了每个订阅的客户端进程,每个进程只需要把消息推送给自己的前端,无需再广播给整个频道:
def join("world:lobby", _message, socket) do PubSub.subscribe(Rotb.PubSub, "zone_1") {:ok, socket} end def handle_info(%{message: message}, socket) do # 用push代替broadcast,仅推送给当前客户端 push(socket, "shout", %{"socket_id" => socket.id, "message" => message}) {:noreply, socket} end def handle_in("shout", payload, socket) do PubSub.broadcast(Rotb.PubSub, "zone_1", %{ message: payload["message"] }) {:noreply, socket} end
更优简化写法(仅频道内广播场景)
如果你的消息只需要在world:lobby频道内传递,完全可以跳过PubSub中转,直接在handle_in里广播到频道,逻辑更简洁且不会出现重复问题:
def join("world:lobby", _message, socket) do {:ok, socket} end def handle_in("shout", payload, socket) do broadcast(socket, "shout", %{"socket_id" => socket.id, "message" => payload["message"]}) {:noreply, socket} end # 移除多余的handle_info和PubSub订阅逻辑
内容的提问来源于stack exchange,提问作者bezzoon
相关产品推荐
相关产品推荐

