I'm trying to extend the example of Phoenix.Channel.reply/2 from the Phoenix documentation into a fully working example of asynchronously replying to Phoenix channel/socket push events:
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
I've reworked the example as follows:
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
...
This solution works, but it doesn't rely on generating and passing a socket_ref with socket_ref(socket)
and on Phoenix.Channel.reply/2. Instead it relies on Phoenix.Channel.broadcast/3.
The documentation implies that reply/2 is specifically used for this scenario of asynchronously replying to socket push events:
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.
When I generate and pass a socket_ref, and rely on Phoenix.Channel.reply/2 for asynchronous replies to socket push, I don't get it to work at all:
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
...
My room_channels.ex handle_info
function is called but reply/2 doesn't seem to send a message down the socket. I see no stacktrace on stderr or any output on stdout to indicate an error either. What is more, keeping track of a socket_ref seems to just add overhead to my code.
What is the benefit of using a socket_ref and reply/2 over my solution with broadcast/3 and how can I get the solution with reply/2 to work?