如何使用Phoenix.Channel.reply/2异步回复频道推送
How to use Phoenix.Channel.reply/2 for async reply to channel push
我正在尝试将 Phoenix 文档中 Phoenix.Channel.reply/2 的示例扩展为异步回复 Phoenix channel/socket 推送事件:
Taken from https://hexdocs.pm/phoenix/Phoenix.Channel.html#reply/2:
def handle_in("work", payload, socket) do
Worker.perform(payload, socket_ref(socket))
{:noreply, socket}
end
def handle_info({:work_complete, result, ref}, socket) do
reply ref, {:ok, result}
{:noreply, socket}
end
我按如下方式修改了示例:
room_channels.ex
...
def handle_in("work", job, socket) do
send worker_pid, {self, job}
{:noreply, socket}
end
def handle_info({:work_complete, result}, socket) do
broadcast socket, "work_complete", %{result: result}
{:noreply, socket}
end
...
worker.ex
...
receive do
{pid, job} ->
result = perform(job) # stub
send pid, {:work_complete, result}
end
...
此解决方案有效,但它不依赖于使用 socket_ref(socket)
和 Phoenix.Channel.reply/2[ 生成和传递 socket_ref =52=]。相反,它依赖于 Phoenix.Channel.broadcast/3.
文档暗示reply/2专门用于这种异步回复socket推送事件的场景:
reply(arg1, arg2)
Replies asynchronously to a socket push.
Useful when you need to reply to a push that can’t otherwise be
handled using the {:reply, {status, payload}, socket} return from your
handle_in callbacks. reply/3 will be used in the rare cases you need
to perform work in another process and reply when finished by
generating a reference to the push with socket_ref/1.
当我生成并传递 socket_ref 并依赖 Phoenix.Channel.reply/2 对套接字推送进行异步回复时,我不完全让它工作:
room_channels.ex
...
def handle_in("work", job, socket) do
send worker_pid, {self, job, socket_ref(socket)}
{:noreply, socket}
end
def handle_info({:work_complete, result, ref}, socket) do
reply ref, {:ok, result}
{:noreply, socket}
end
...
worker.ex
...
receive do
{pid, job, ref} ->
result = perform(job) # stub
send pid, {:work_complete, result, ref}
end
...
我的 room_channels.ex handle_info
函数被调用,但 reply/2 似乎没有通过套接字发送消息。我在 stderr 上没有看到任何堆栈跟踪,也没有在 stdout 上看到任何指示错误的输出。更重要的是,跟踪 socket_ref 似乎只会增加我的代码开销。
使用 socket_ref 和 reply/2 比 broadcast/3[=52 的解决方案有什么好处=] 以及如何使用 reply/2 解决方案?
我错了,Phoenix.Channel.reply/2 的例子可以工作:
room_channels.ex
...
def handle_in("work", job, socket) do
send worker_pid, {self, job, socket_ref(socket)}
{:noreply, socket}
end
def handle_info({:work_complete, result, ref}, socket) do
reply ref, {:ok, result}
{:noreply, socket}
end
...
worker.ex
...
receive do
{pid, job, ref} ->
result = perform(job) # stub
send pid, {:work_complete, result, ref}
end
...
在我的实现中,我犯了一个错误,即使用 {:reply, :ok, socket}
的 return 值而不是 {:noreply, socket}
发送对事件推送的同步回复。
仔细检查从服务器发送到客户端的 websocket 帧,我发现浏览器确实从 reply ref, {:ok, result}
收到了我的服务器回复,但从未调用相关的回调。
Phoenix 的 Socket.js 客户端库似乎对每个推送事件最多接受一个回复。
希望这次谈话我还不算太晚。
我成功地使用了上面的代码,并在 javascript 中使用了回调。
诀窍是监听 phx_reply
事件。在 priv/static/app.js
中,每个 Channel
javascript 对象都有一个在 CHANNEL_EVENTS
中预定义的列表(行并设置为在以下代码块中监听它:
this.on(CHANNEL_EVENTS.reply, function (payload, ref) {
_this2.trigger(_this2.replyEventName(ref), payload);
});
我所做的是在通道 on
回调中,我监听 phx_reply
事件:
channel.on("phx_reply", (data) => {
console.log("DATA ", data);
// Process the data
}
这已经在 Elixir 1.3 和 Phoenix 1.2 上测试过
希望对您有所帮助!
我正在尝试将 Phoenix 文档中 Phoenix.Channel.reply/2 的示例扩展为异步回复 Phoenix channel/socket 推送事件:
Taken from https://hexdocs.pm/phoenix/Phoenix.Channel.html#reply/2:
def handle_in("work", payload, socket) do Worker.perform(payload, socket_ref(socket)) {:noreply, socket} end def handle_info({:work_complete, result, ref}, socket) do reply ref, {:ok, result} {:noreply, socket} end
我按如下方式修改了示例:
room_channels.ex
...
def handle_in("work", job, socket) do
send worker_pid, {self, job}
{:noreply, socket}
end
def handle_info({:work_complete, result}, socket) do
broadcast socket, "work_complete", %{result: result}
{:noreply, socket}
end
...
worker.ex
...
receive do
{pid, job} ->
result = perform(job) # stub
send pid, {:work_complete, result}
end
...
此解决方案有效,但它不依赖于使用 socket_ref(socket)
和 Phoenix.Channel.reply/2[ 生成和传递 socket_ref =52=]。相反,它依赖于 Phoenix.Channel.broadcast/3.
文档暗示reply/2专门用于这种异步回复socket推送事件的场景:
reply(arg1, arg2)
Replies asynchronously to a socket push.
Useful when you need to reply to a push that can’t otherwise be handled using the {:reply, {status, payload}, socket} return from your handle_in callbacks. reply/3 will be used in the rare cases you need to perform work in another process and reply when finished by generating a reference to the push with socket_ref/1.
当我生成并传递 socket_ref 并依赖 Phoenix.Channel.reply/2 对套接字推送进行异步回复时,我不完全让它工作:
room_channels.ex
...
def handle_in("work", job, socket) do
send worker_pid, {self, job, socket_ref(socket)}
{:noreply, socket}
end
def handle_info({:work_complete, result, ref}, socket) do
reply ref, {:ok, result}
{:noreply, socket}
end
...
worker.ex
...
receive do
{pid, job, ref} ->
result = perform(job) # stub
send pid, {:work_complete, result, ref}
end
...
我的 room_channels.ex handle_info
函数被调用,但 reply/2 似乎没有通过套接字发送消息。我在 stderr 上没有看到任何堆栈跟踪,也没有在 stdout 上看到任何指示错误的输出。更重要的是,跟踪 socket_ref 似乎只会增加我的代码开销。
使用 socket_ref 和 reply/2 比 broadcast/3[=52 的解决方案有什么好处=] 以及如何使用 reply/2 解决方案?
我错了,Phoenix.Channel.reply/2 的例子可以工作:
room_channels.ex
...
def handle_in("work", job, socket) do
send worker_pid, {self, job, socket_ref(socket)}
{:noreply, socket}
end
def handle_info({:work_complete, result, ref}, socket) do
reply ref, {:ok, result}
{:noreply, socket}
end
...
worker.ex
...
receive do
{pid, job, ref} ->
result = perform(job) # stub
send pid, {:work_complete, result, ref}
end
...
在我的实现中,我犯了一个错误,即使用 {:reply, :ok, socket}
的 return 值而不是 {:noreply, socket}
发送对事件推送的同步回复。
仔细检查从服务器发送到客户端的 websocket 帧,我发现浏览器确实从 reply ref, {:ok, result}
收到了我的服务器回复,但从未调用相关的回调。
Phoenix 的 Socket.js 客户端库似乎对每个推送事件最多接受一个回复。
希望这次谈话我还不算太晚。
我成功地使用了上面的代码,并在 javascript 中使用了回调。
诀窍是监听 phx_reply
事件。在 priv/static/app.js
中,每个 Channel
javascript 对象都有一个在 CHANNEL_EVENTS
中预定义的列表(行并设置为在以下代码块中监听它:
this.on(CHANNEL_EVENTS.reply, function (payload, ref) {
_this2.trigger(_this2.replyEventName(ref), payload);
});
我所做的是在通道 on
回调中,我监听 phx_reply
事件:
channel.on("phx_reply", (data) => {
console.log("DATA ", data);
// Process the data
}
这已经在 Elixir 1.3 和 Phoenix 1.2 上测试过
希望对您有所帮助!