Elm, phoenix和elixir对我来说是很新的,所以我想我应该做一个简单的通道测试应用程序来测试phoenix通道的使用。这个应用程序也有其他的东西,因为它是由旧的"零件"制成的,但请原谅我。
这个想法是,您有几个生成服务器对凤凰端点进行http调用。基本上,它们只是更新代理进程中保存的列表。该列表通过凤凰频道显示在Elm应用程序中。我们的目标只是看看如果代理状态通过几个进程频繁更新会发生什么。
这就是我目前得到的。我有凤凰网站与榆树应用程序设置和一个单独的Elixir应用程序与genserver进行更新。一切工作正常大约20秒,但随后通道连接被切断,并没有重新建立,除非我点击刷新浏览器。我可以从日志中看到后端仍然工作正常,浏览器控制台也没有错误。那么这到底是怎么回事呢?我认为,通道连接应该自动重新连接,如果丢失,为什么它是断开连接?
我猜问题出在榆树-凤凰-插座。下面是它在elm应用程序中的设置:
socketServer : String
socketServer =
"ws://localhost:4000/socket/websocket"
initPhxSocket : Phoenix.Socket.Socket Msg
initPhxSocket =
Phoenix.Socket.init socketServer
|> Phoenix.Socket.withDebug
|> Phoenix.Socket.on "new:heartbeats" "heartbeats:lobby" ReceiveHeartbeats
后端广播是这样完成的:
defmodule AbottiWeb.ApiController do
use AbottiWeb.Web, :controller
def index(conn, _params) do
beats = AbottiWeb.HeartbeatAgent.get()
json conn, beats
end
def heartbeat(conn, %{"agent" => agent} ) do
AbottiWeb.HeartbeatAgent.update(agent)
beats = AbottiWeb.HeartbeatAgent.get()
AbottiWeb.Endpoint.broadcast("heartbeats:lobby", "new:heartbeats", beats)
json conn, :ok
end
end
所以本质上,生成服务器不断地调用心跳端点。但我怀疑问题出在这里。另一种可能的问题在于通道设置,看起来像这样:
user_socket.ex:
defmodule AbottiWeb.UserSocket do
use Phoenix.Socket
channel "heartbeats:*", AbottiWeb.HeartbeatChannel
transport :websocket, Phoenix.Transports.WebSocket
def connect(_params, socket) do
{:ok, socket}
end
def id(_socket), do: nil
end
和heartbeat_channel.ex:
defmodule AbottiWeb.HeartbeatChannel do
use AbottiWeb.Web, :channel
require Logger
def join("heartbeats:lobby", payload, socket) do
Logger.debug "Hearbeats:lobby joined: #{inspect payload}"
if authorized?(payload) do
{:ok, socket}
else
{:error, %{reason: "unauthorized"}}
end
end
# Channels can be used in a request/response fashion
# by sending replies to requests from the client
def handle_in("ping", payload, socket) do
{:reply, {:ok, payload}, socket}
end
# It is also common to receive messages from the client and
# broadcast to everyone in the current topic (heartbeats:lobby).
def handle_in("shout", payload, socket) do
broadcast socket, "shout", payload
{:noreply, socket}
end
# This is invoked every time a notification is being broadcast
# to the client. The default implementation is just to push it
# downstream but one could filter or change the event.
def handle_out(event, payload, socket) do
Logger.debug "Broadcasting #{inspect event} #{inspect payload}"
push socket, event, payload
{:noreply, socket}
end
# Add authorization logic here as required.
defp authorized?(_payload) do
true
end
end
知道是什么问题吗?我猜是非常简单的东西。
Ok,我现在知道套接字传输超时了。但为什么会这样呢?
我是这样解决的:
transport :websocket, Phoenix.Transports.WebSocket,
timeout: :infinity
我不知道这有多有害,但这是一个测试应用程序,这并不重要。