Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: Add SIGHUP and SIGTERM handling to coder server #3543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions cli/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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...)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Naming this notifyCtx here means that during startup, and interrupt signal won't abort the process up until we start listening <-notifyCtx.Done().

The reason for this is that we have certain services that begin their shutdown procedure on context cancellation, but we want to control the order in which things are shut down.

I think it's acceptable that after starting, ctrl+c won't close coder server until the initial startup sequence is complete. But it's possible to work around this by monitoring the notifyCtx separately for parts of the startup where we want an early exit.

defer notifyStop()

// Clean up idle connections at the end, e.g.
// embedded-postgres can leave an idle connection
// which is caught by goleaks.
Expand Down Expand Up @@ -521,22 +534,13 @@ 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():
exitErr = ctx.Err()
case <-notifyCtx.Done():
exitErr = notifyCtx.Err()
_, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Bold.Render(
"Interrupt caught, gracefully exiting. Use ctrl+\\ to force quit",
))
Expand Down
14 changes: 14 additions & 0 deletions cli/signal_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build !windows

package cli

import (
"os"
"syscall"
)

var interruptSignals = []os.Signal{
os.Interrupt,
syscall.SIGTERM,
syscall.SIGHUP,
}
9 changes: 9 additions & 0 deletions cli/signal_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build windows

package cli

import (
"os"
)

var interruptSignals = []os.Signal{os.Interrupt}