Elm、phoenix、および elixir は私にとってまったく新しいものなので、phoenix チャネルの使用をテストするために、チャネル テスト アプリを簡単なサンプル アプリにしようと考えました。アプリは古い「部品」から作られているため、他のものも含まれていますが、これについてはご容赦ください。
アイデアは、フェニックスエンドポイントへの http 呼び出しを行う複数の genserver があるということです。基本的に、エージェント プロセスに保持されているリストを更新しているだけです。そのリストは、phoenix チャネルを介して Elm アプリに表示されます。目標は、エージェントの状態が複数のプロセスで頻繁に更新されるとどうなるかを確認することでした。
これが私がこれまでに持っているものです。Elm アプリのセットアップを含むフェニックス サイトと、更新を行う genservers を含む別の Elixir アプリがあります。すべてが約 20 秒間正常に動作しますが、チャネル接続が切断され、ブラウザで更新しない限り再確立されません。バックエンドがまだ正常に動作しており、ブラウザー コンソールにもエラーがないことをログから確認できます。それで、ここでの取引は何ですか?チャンネル接続が失われた場合、自動的に再接続するはずだと思っていましたが、なぜ切断されるのでしょうか?
問題はelm-phoenix-socket にあると推測しています。これは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
したがって、本質的に、genserver はそのハートビート エンドポイントに対して常に呼び出しを行っています。私は問題がここにあるとは思わない。問題が存在する別の可能性は、次のようなチャネル設定です。
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
それで、問題は何ですか?それは本当に単純なことだと思います。
わかりました、ソケット転送がタイムアウトしたことがわかりました。しかし、なぜそれを行うのですか?