diff --git a/internal/bootstrap/router_bootstrap.go b/internal/bootstrap/router_bootstrap.go index 3469fedb..a7c03b39 100644 --- a/internal/bootstrap/router_bootstrap.go +++ b/internal/bootstrap/router_bootstrap.go @@ -98,7 +98,7 @@ func (app *BootstrapApp) calculateListenerPolicy() []Listener { l := []Listener{} if !app.config.Server.ConcurrentListenersEnabled { - if app.config.Tailscale.Enabled { + if app.services.tailscaleService != nil { l = append(l, ListenerTailscale) return l } @@ -116,7 +116,7 @@ func (app *BootstrapApp) calculateListenerPolicy() []Listener { l = append(l, ListenerUnix) } - if app.config.Tailscale.Enabled { + if app.services.tailscaleService != nil { l = append(l, ListenerTailscale) } @@ -205,7 +205,12 @@ func (app *BootstrapApp) serve(listener net.Listener, server *http.Server, name ctx, cancel := context.WithTimeout(context.Background(), model.GracefulShutdownTimeout*time.Second) defer cancel() err := server.Shutdown(ctx) - if err != nil { + if err != nil && + // With tailscale, the goroutine for shutting down the tailscale connection + // runs first and causes the connection the tailscale listener is running on to close + // first so, the shutdown fails + // TODO: add priority to the goroutine shutdowns + !errors.Is(err, net.ErrClosed) { app.log.App.Error().Err(err).Msgf("Failed to shutdown %s listener gracefully", name) } listener.Close() diff --git a/internal/service/tailscale_service.go b/internal/service/tailscale_service.go index 52275882..25f83e6d 100644 --- a/internal/service/tailscale_service.go +++ b/internal/service/tailscale_service.go @@ -15,6 +15,10 @@ import ( "tailscale.com/tsnet" ) +var ( + TsnetErrClosed = errors.New("tsnet: use of closed network connection") +) + type TailscaleWhoisResponse struct { UserID string LoginName string @@ -99,10 +103,10 @@ func (ts *TailscaleService) watchAndClose() { ts.srv = nil ts.mu.Unlock() if ln != nil { - (*ts.ln).Close() + (*ln).Close() } if srv != nil { - ts.srv.Close() + srv.Close() } }