Closed axelson closed 7 months ago
Nice find! Do you think we could the Application.stop callback instead? Or is that too late?
Application.stop
would be too late, although Application.prep_stop
could work. And I tried making that change in dbb27be2671b9119e257169371f052a12e4ab093. However, after making that change and thinking about it I realized that there is also a race condition on startup. If a log message comes in between attach_logger()
and the Registry starting up then the WebConsoleLogger handler will fail and become detached. Here's a sequence diagram illustrating that (you can probably understand without the sequence diagram but it's good practice for me to create one and maybe it'll help someone in the future):
sequenceDiagram
participant LoggerHandler
participant Registry
participant OtherDep
LoggerHandler->>LoggerHandler: attach
OtherDep->>LoggerHandler: log message
LoggerHandler->>Registry: Registry.dispatch
Note left of LoggerHandler: Handler fails with<br/>{removed_failing_handler,'Elixir.Phoenix.LiveReloader.WebConsoleLogger'}<br />This happens because the Registry has not yet been started
Registry->>Registry: startup
If we instead move all the startup and initialization into the supervision tree then we can ensure that on startup the handler is not attached before the Registry starts and also ensure that the handler is detached before the Registry stops. Here's a sequence diagram of that:
sequenceDiagram
participant LoggerHandler
participant Registry
participant OtherDep
Registry->>Registry: startup
LoggerHandler->>LoggerHandler: attach
OtherDep->>LoggerHandler: log message
LoggerHandler->>Registry: Registry.dispatch
Note right of Registry: success!
While we could keep the handler_detach
call in application.ex
to me it makes more sense to keep the attach and detach both in the same module because then it's easier to follow and understand the flow. In 82ab0607832fdd37aa611617a763eadbb62cce67 I've moved the attach/detach logic back into the supervision tree but moved the GenServer logic into WebConsoleLogger
itself.
:green_heart: :blue_heart: :purple_heart: :yellow_heart: :heart:
Before this commit when executing a clean shutdown via
System.stop()
errors would be printed to the console:Logger - error: {Logger - error: removed_failing_handler,'Elixir.Phoenix.LiveReloader.WebConsoleLogger'}
(plus about 7 errors at the debug level)
This is avoided by controlling the application startup and shutdown via a new
WebConsoleLoggerInitializer
GenServer that runsdetach_logger
before thePhoenix.LiveReloader.WebConsoleLoggerRegistry
is shutdown.This is important because with all the error messages it is hard to tell if your phoenix-based application is shutting down cleanly.
This can be tested by starting a phoenix application that uses
:phoenix_live_reload
withiex -S mix phx.server
and then runningSystem.stop
. No error logs from:phoenix_live_reload
should be printed.Here's the logs that I was seeing without this change (they're a little hard to read since they got interspersed with each other):