diff --git a/CHANGELOG.md b/CHANGELOG.md index dcfb8b9..9e91605 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,8 +31,11 @@ - Add configuration option to allow Tailscale clients to use a random WireGuard port. [kb/1181/firewalls](https://tailscale.com/kb/1181/firewalls) [#624](https://github.com/juanfont/headscale/pull/624) - Improve obtuse UX regarding missing configuration (`ephemeral_node_inactivity_timeout` not set) [#639](https://github.com/juanfont/headscale/pull/639) - Fix nodes being shown as 'offline' in `tailscale status` [648](https://github.com/juanfont/headscale/pull/648) +- Fix nodes being shown as 'offline' in `tailscale status` [#648](https://github.com/juanfont/headscale/pull/648) +- Improve shutdown behaviour [#651](https://github.com/juanfont/headscale/pull/651) - Drop Gin as web framework in Headscale [648](https://github.com/juanfont/headscale/pull/648) + ## 0.15.0 (2022-03-20) **Note:** Take a backup of your database before upgrading. diff --git a/app.go b/app.go index e6a5121..952a180 100644 --- a/app.go +++ b/app.go @@ -55,12 +55,13 @@ const ( ) const ( - AuthPrefix = "Bearer " - Postgres = "postgres" - Sqlite = "sqlite3" - updateInterval = 5000 - HTTPReadTimeout = 30 * time.Second - privateKeyFileMode = 0o600 + AuthPrefix = "Bearer " + Postgres = "postgres" + Sqlite = "sqlite3" + updateInterval = 5000 + HTTPReadTimeout = 30 * time.Second + HTTPShutdownTimeout = 3 * time.Second + privateKeyFileMode = 0o600 registerCacheExpiration = time.Minute * 15 registerCacheCleanup = time.Minute * 20 @@ -685,8 +686,13 @@ func (h *Headscale) Serve() error { h.shutdownChan <- struct{}{} // Gracefully shut down servers - promHTTPServer.Shutdown(ctx) - httpServer.Shutdown(ctx) + ctx, cancel := context.WithTimeout(context.Background(), HTTPShutdownTimeout) + if err := promHTTPServer.Shutdown(ctx); err != nil { + log.Error().Err(err).Msg("Failed to shutdown prometheus http") + } + if err := httpServer.Shutdown(ctx); err != nil { + log.Error().Err(err).Msg("Failed to shutdown http") + } grpcSocket.GracefulStop() // Close network listeners @@ -697,7 +703,21 @@ func (h *Headscale) Serve() error { // Stop listening (and unlink the socket if unix type): socketListener.Close() + // Close db connections + db, err := h.db.DB() + if err != nil { + log.Error().Err(err).Msg("Failed to get db handle") + } + err = db.Close() + if err != nil { + log.Error().Err(err).Msg("Failed to close db") + } + + log.Info(). + Msg("Headscale stopped") + // And we're done: + cancel() os.Exit(0) } } diff --git a/cmd/headscale/cli/utils.go b/cmd/headscale/cli/utils.go index 327c8c1..c07e3a2 100644 --- a/cmd/headscale/cli/utils.go +++ b/cmd/headscale/cli/utils.go @@ -55,6 +55,7 @@ func getHeadscaleCLIClient() (context.Context, v1.HeadscaleServiceClient, *grpc. Err(err). Caller(). Msgf("Failed to load configuration") + os.Exit(-1) // we get here if logging is suppressed (i.e., json output) } log.Debug(). @@ -116,6 +117,7 @@ func getHeadscaleCLIClient() (context.Context, v1.HeadscaleServiceClient, *grpc. conn, err := grpc.DialContext(ctx, address, grpcOptions...) if err != nil { log.Fatal().Caller().Err(err).Msgf("Could not connect: %v", err) + os.Exit(-1) // we get here if logging is suppressed (i.e., json output) } client := v1.NewHeadscaleServiceClient(conn)