diff --git a/lib/phoenix/socket.ex b/lib/phoenix/socket.ex index 18a4c9eb99..742e74342d 100644 --- a/lib/phoenix/socket.ex +++ b/lib/phoenix/socket.ex @@ -556,7 +556,11 @@ defmodule Phoenix.Socket do end def __info__(%Broadcast{event: "disconnect"}, state) do - {:stop, {:shutdown, :disconnected}, state} + # Close code 1001 ("Going Away") signals the client that the connection + # is intentionally closed but a reconnect is expected — phoenix.js gates + # reconnects behind a closeCode !== 1000 check. + # See https://github.com/mtrudel/bandit/issues/582. + {:stop, {:shutdown, :disconnected}, 1001, state} end def __info__(:socket_drain, state) do diff --git a/lib/phoenix/transports/long_poll_server.ex b/lib/phoenix/transports/long_poll_server.ex index e3a5f23d8d..6875efa4b6 100644 --- a/lib/phoenix/transports/long_poll_server.ex +++ b/lib/phoenix/transports/long_poll_server.ex @@ -117,6 +117,10 @@ defmodule Phoenix.Transports.LongPoll.Server do {:stop, reason, handler_state} -> state = %{state | handler: {handler, handler_state}} {:stop, reason, state} + + {:stop, reason, _code, handler_state} -> + state = %{state | handler: {handler, handler_state}} + {:stop, reason, state} end end diff --git a/test/phoenix/socket/socket_test.exs b/test/phoenix/socket/socket_test.exs index 03971cd2c0..1a7a1898af 100644 --- a/test/phoenix/socket/socket_test.exs +++ b/test/phoenix/socket/socket_test.exs @@ -137,4 +137,20 @@ defmodule Phoenix.SocketTest do assert DrainerSpecSocket.drainer_spec(drainer: false, endpoint: Endpoint) == :ignore end end + + describe "__info__/2" do + alias Phoenix.Socket.Broadcast + + test "disconnect broadcast emits close code 1001 so phoenix.js reconnects" do + # phoenix.js gates reconnects on `closeCode !== 1000`. + # Servers might interpret `{:shutdown, :disconnected}` + # as code 1000, so we pass 1001 explicitly to force a retry. + # See https://github.com/mtrudel/bandit/issues/582. + state = make_ref() + msg = %Broadcast{topic: "t", event: "disconnect", payload: %{}} + + assert {:stop, {:shutdown, :disconnected}, 1001, ^state} = + Phoenix.Socket.__info__(msg, state) + end + end end