From de1df9d5b5f795c4a07de930644960a2fc097b38 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 18 Aug 2022 11:51:56 +0300 Subject: [PATCH 1/3] fix: Add `SIGHUP` and `SIGTERM` handling to `coder server` To prevent additional signals from aborting program execution, signal handling was moved to the beginning of the main function, this ensures that signals stays registered for the entire shutdown procedure. Fixes #1529 --- cli/server.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/cli/server.go b/cli/server.go index 86016d9c9bd7a..e7233b5915324 100644 --- a/cli/server.go +++ b/cli/server.go @@ -127,6 +127,19 @@ func server() *cobra.Command { ctx, cancel := context.WithCancel(cmd.Context()) defer cancel() + // Register signals early on so that graceful shutdown can't + // be interrupted by additional signals. Note that we avoid + // shadowing cancel() (from above) here because notifyStop() + // restores default behavior for the signals. This protects + // the shutdown sequence from abrubtly terminating things + // like: database migrations, provisioner work, workspace + // cleanup in dev-mode, etc. + // + // To get out of a graceful shutdown, the user can send + // SIGQUIT with ctrl+\ or SIGKILL with `kill -9`. + notifyCtx, notifyStop := signal.NotifyContext(ctx, interruptSignals...) + defer notifyStop() + // Clean up idle connections at the end, e.g. // embedded-postgres can leave an idle connection // which is caught by goleaks. @@ -521,21 +534,12 @@ func server() *cobra.Command { // such as via the systemd service. _ = config.URL().Write(client.URL.String()) - // Because the graceful shutdown includes cleaning up workspaces in dev mode, we're - // going to make it harder to accidentally skip the graceful shutdown by hitting ctrl+c - // two or more times. So the stopChan is unlimited in size and we don't call - // signal.Stop() until graceful shutdown finished--this means we swallow additional - // SIGINT after the first. To get out of a graceful shutdown, the user can send SIGQUIT - // with ctrl+\ or SIGTERM with `kill`. - ctx, stop := signal.NotifyContext(ctx, os.Interrupt) - defer stop() - // Currently there is no way to ask the server to shut // itself down, so any exit signal will result in a non-zero // exit of the server. var exitErr error select { - case <-ctx.Done(): + case <-notifyCtx.Done(): exitErr = ctx.Err() _, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Bold.Render( "Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit", From 501fdd2b1cd51bb2394a00625e7b777e6d57bcfc Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 18 Aug 2022 11:55:05 +0300 Subject: [PATCH 2/3] fix: Add missing signal files --- cli/signal_unix.go | 14 ++++++++++++++ cli/signal_windows.go | 9 +++++++++ 2 files changed, 23 insertions(+) create mode 100644 cli/signal_unix.go create mode 100644 cli/signal_windows.go diff --git a/cli/signal_unix.go b/cli/signal_unix.go new file mode 100644 index 0000000000000..7d2cd0e5022c5 --- /dev/null +++ b/cli/signal_unix.go @@ -0,0 +1,14 @@ +//go:build !windows + +package cli + +import ( + "os" + "syscall" +) + +var interruptSignals = []os.Signal{ + os.Interrupt, + syscall.SIGTERM, + syscall.SIGHUP, +} diff --git a/cli/signal_windows.go b/cli/signal_windows.go new file mode 100644 index 0000000000000..17652adfb626d --- /dev/null +++ b/cli/signal_windows.go @@ -0,0 +1,9 @@ +//go:build windows + +package cli + +import ( + "os" +) + +var interruptSignals = []os.Signal{os.Interrupt} From cc0b7bf9e526727b0b7e70c53691e4052f2fe8fe Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Thu, 18 Aug 2022 12:43:34 +0300 Subject: [PATCH 3/3] fix: Return the correct err --- cli/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/server.go b/cli/server.go index e7233b5915324..126ea0bc8204b 100644 --- a/cli/server.go +++ b/cli/server.go @@ -540,7 +540,7 @@ func server() *cobra.Command { var exitErr error select { case <-notifyCtx.Done(): - exitErr = ctx.Err() + exitErr = notifyCtx.Err() _, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Bold.Render( "Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit", ))