Build the HTTP router before the server starts (closes #104)
check / check (push) Successful in 2m22s

The fx OnStart hook started a goroutine that built the router and then
began serving, so OnStart returned before the router existed. Code that
served requests through the started Server, as the internal/handlers
tests do, raced with that goroutine or hit a nil router.

OnStart now configures the server, enables Sentry and builds the router
itself, and only then starts serving in the background. Sentry is set up
first because the routes depend on whether it is enabled. Run, whose
only caller was that hook, is folded into it.

Model: opus-5-5
This commit is contained in:
clawbot
2026-09-29 10:40:36 +00:00
parent f829f9e3da
commit 6a514b565c
+8 -10
View File
@@ -71,7 +71,14 @@ func New(
lifecycle.Append(fx.Hook{ lifecycle.Append(fx.Hook{
OnStart: func(_ context.Context) error { OnStart: func(_ context.Context) error {
srv.startupTime = time.Now() srv.startupTime = time.Now()
go srv.Run() //nolint:contextcheck
// Build the router before OnStart returns, so srv can
// handle requests as soon as the app has started.
srv.configure()
srv.enableSentry()
srv.SetupRoutes()
go srv.serve() //nolint:contextcheck
return nil return nil
}, },
@@ -83,13 +90,6 @@ func New(
return srv, nil return srv, nil
} }
// Run starts the server configuration, Sentry, and begins serving.
func (srv *Server) Run() {
srv.configure()
srv.enableSentry()
srv.serve()
}
// ServeHTTP delegates to the chi router. // ServeHTTP delegates to the chi router.
func (srv *Server) ServeHTTP( func (srv *Server) ServeHTTP(
writer http.ResponseWriter, writer http.ResponseWriter,
@@ -202,8 +202,6 @@ func (srv *Server) serveUntilShutdown() {
Handler: srv, Handler: srv,
} }
srv.SetupRoutes()
srv.log.Info( srv.log.Info(
"http begin listen", "listenaddr", listenAddr, "http begin listen", "listenaddr", listenAddr,
) )