Hi everyone,
It would be nice to have an equivalent to the debug_errors
configuration option from Phoenix.Endpoint
in Phoenix.LiveView
for raised errors in the connected state.
The configuration setting’s effect could be as simple as being more vocal in logs about any errors encountered in the connected state.
The following section contains an example of why it can be helpful.
I cornered myself in an infinite reloading loop while working with LiveView.
In short, my code behaves differently in an HTTP mount than on a connected mount. It loads data only on connected mounts.
Alas, the connected mount’s implementation was buggy and raised an Ecto
error. The error implements Plug.Exception
and results in the 404 plug_status
.
LiveView sends a reload command to its clients if connected mounts encounter errors in 400…499 range:
rescue
exception ->
status = Plug.Exception.status(exception)
if status >= 400 and status < 500 do
GenServer.reply(from, {:error, %{reason: "reload", status: status}})
{:stop, :shutdown, :no_state}
else
reraise(exception, __STACKTRACE__)
end
end
You can see where this is going:
- My HTTP mount renders without issues
- My connected mount raised an exception with a 400…499
plug_status
- LiveView sends
reload
to clients - LiveView clients happily reload the page and we are back and the step one.
While it’s an expected behavior, it’s nevertheless a frustrating one. One of the reasons is that there are no errors in the logs. They look fine, showing the HTTP mount followed by the connected mount over and over again:
[info] GET /
[debug] Processing with PhoenixPlayground.Router.DelegateLive.index/2
Parameters: %{}
Pipelines: [:browser]
[info] Sent 200 in 252µs
[info] CONNECTED TO Phoenix.LiveView.Socket in 26µs
Transport: :websocket
Serializer: Phoenix.Socket.V2.JSONSerializer
Parameters: %{"vsn" => "2.0.0"}
[debug] MOUNT PhoenixPlayground.Router.DelegateLive
Parameters: %{}
Session: %{}
Mind that the behavior manifests only with errors that have 400…499 plug_status
.
The gist of the behavior looks like this:
Mix.install([
{:phoenix_playground, "~> 0.1.0"}
])
defmodule MyError do
defexception plug_status: 400, message: nil
end
defmodule DemoLive do
use Phoenix.LiveView
def mount(_params, _session, socket) do
if connected?(socket), do: raise MyError, message: "oops"
{:ok, socket}
end
def render(assigns) do
~H"""
<p>Page</p>
"""
end
end
PhoenixPlayground.start(live: DemoLive)
What do you all think?