fix(httpserver): bind port synchronously in OnStart so bind errors propagate
Previously ListenAndServe ran entirely in a goroutine, so a port-in-use error was only logged and the launcher received nil from OnStart — leaving the application running without an HTTP server. Replace with net.Listen (synchronous) + srv.Serve(ln) (goroutine). A bind failure now returns an error from OnStart, which the launcher treats as fatal and triggers a clean shutdown immediately. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -80,7 +81,10 @@ func (s *httpServer) OnInit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnStart starts the HTTP server in a background goroutine.
|
||||
// OnStart binds the TCP listener synchronously so that a port conflict returns
|
||||
// an error immediately — allowing the launcher to trigger a clean shutdown
|
||||
// instead of running silently without an HTTP server. The accepted connections
|
||||
// are then served in a background goroutine.
|
||||
func (s *httpServer) OnStart() error {
|
||||
host := s.cfg.Host
|
||||
if host == "" {
|
||||
@@ -90,16 +94,23 @@ func (s *httpServer) OnStart() error {
|
||||
if port == 0 {
|
||||
port = 8080
|
||||
}
|
||||
addr := fmt.Sprintf("%s:%d", host, port)
|
||||
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("httpserver: bind %s: %w", addr, err)
|
||||
}
|
||||
|
||||
s.srv = &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", host, port),
|
||||
Addr: addr,
|
||||
Handler: s.Router,
|
||||
ReadTimeout: s.cfg.ReadTimeout,
|
||||
WriteTimeout: s.cfg.WriteTimeout,
|
||||
IdleTimeout: s.cfg.IdleTimeout,
|
||||
}
|
||||
s.logger.Info("httpserver: starting", "addr", s.srv.Addr)
|
||||
s.logger.Info("httpserver: starting", "addr", addr)
|
||||
go func() {
|
||||
if err := s.srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
if err := s.srv.Serve(ln); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
s.logger.Error("httpserver: fatal error", err)
|
||||
}
|
||||
}()
|
||||
|
||||
Reference in New Issue
Block a user