Hey folks, I’m deploying a Phoenix 1.4 umbrella app with multiple web endpoints to Heroku, so I need a single endpoint that will reverse proxy my web_apps and their websockets.
The following code is working properly to dispatch plain HTTP traffic between my apps, but Cowboy crashes when loading live_reload websockets.
I wrote this code from cowboy 1.0 examples, and I guess the way I setup dispatch has changed. But I’m struggling at reading cowboy 2.5 documentation …
My proxy application :
defmodule MyProxy.Application do
alias Plug.Cowboy
use Application
def start(_type, _args) do
import Supervisor.Spec, warn: false
port = (System.get_env("PORT") || "5000") |> String.to_integer
cowboy = Cowboy.child_spec(
scheme: :http,
plug: MyProxy.Plug,
options: [
port: port,
dispatch: [{:_, [
my_app_web_live_reload(),
my_other_app_live_reload(),
proxy()
]}]
]
)
children = [cowboy]
opts = [strategy: :one_for_one, name: MyProxy.Supervisor]
Supervisor.start_link(children, opts)
end
defp my_app_web_live_reload do
{
"/my_app/live_reload/socket/websocket",
Phoenix.Endpoint.CowboyWebSocket,
{
Phoenix.Transports.WebSocket,
{MyApp.Endpoint, Phoenix.LiveReloader.Socket, :websocket}
}
}
end
defp my_other_app_live_reload do
{
"/my_other_app/live_reload/socket/websocket",
Phoenix.Endpoint.CowboyWebSocket,
{
Phoenix.Transports.WebSocket,
{MyOtherApp.Endpoint, Phoenix.LiveReloader.Socket, :websocket}
}
}
end
defp proxy do
{:_, Cowboy.Handler, {MyProxy.Plug, []}}
end
end
and the proxy plug:
defmodule MyProxy.Plug do
def init(options) do
options
end
def call(conn, _opts) do
if conn.request_path =~ ~r{/my_app} do
MyApp.Endpoint.call(conn, [])
else
MyOtherApp.Endpoint.call(conn, [])
end
end
end
The cowboy error
[error] Ranch protocol #PID<0.1043.0> of listener MyProxy.Plug.HTTP (connection #PID<0.1042.0>, stre
am id 1) terminated
** (exit) :undef
[error] :gen_event handler :error_logger_lager_h installed in :error_logger terminating
** (CaseClauseError) no case clause matching: [MyProxy.Plug.HTTP, #PID<0.1042.0>, 1, #PID<0.1043.0>,
:undef, [{Phoenix.Endpoint.CowboyWebSocket, :init, [%{bindings: %{}, body_length: 0, cert: :undefin
ed, has_body: false, headers: %{"accept-encoding" => "gzip, deflate, br", "accept-language" => "fr-F
R,fr;q=0.9,en-US;q=0.8,en;q=0.7", "cache-control" => "no-cache", "connection" => "Upgrade" , "host"
=> "localhost:5000", "origin" => "http://localhost:5000", "pragma" => "no-cache", "sec-websocket-ext
ensions" => "permessage-deflate; client_max_window_bits", "sec-websocket-key" => "LiihXA7p3GimivqsYH
hjqg==", "sec-websocket-version" => "13", "upgrade" => "websocket", "user-agent" => "Mozilla/5.0 (Ma
cintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/
537.36"}, host: "localhost", host_info: :undefined, method: "GET", path: "/my_app/live_reload/socket
/websocket", path_info: :undefined, peer: {{127, 0, 0, 1}, 54652}, pid: #PID<0.1042.0>, port: 5000,
qs: "vsn=2.0.0", ref: MyProxy.Plug.HTTP, scheme: "http", sock: {{127, 0, 0, 1}, 5000}, streamid: 1,
version: :"HTTP/1.1"}, {Phoenix.Transports.WebSocket, {MyApp.Endpoint, Phoenix.LiveReloader.Socket,
:websocket}}], []}, {:cowboy_handler, :execute, 2, [file: 'my_app/deps/cowboy/src/cowboy_handler.erl
', line: 41]}, {:cowboy_stream_h, :execute, 3, [file: 'my_app/deps/cowboy/src/cowboy_stream_h.erl',
line: 293]}, {:cowboy_stream_h, :request_process, 3, [file: 'my_app/deps/cowboy/src/cowboy_stream_h.
erl', line: 271]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 247]}]]