1aa65e6863
Since the main SIGINT handler is running as a goroutine, the main goroutine must be kept active long enough for it to finish or it will be nuked when the main goroutine exits. This commit makes that happen by slightly modifying how it waits for shutdown. Rather than having the main goroutine only wait for the server to shutdown, there is now a shutdown channel that is used to signal the main goroutine to shutdown for all cases such as a graceful shutdown, a scheduled shutdown, an RPC stop, or a SIGINT. While here, also add a few prints to indicate a SIGINT was received and the shutdown progress.
56 lines
1.6 KiB
Go
56 lines
1.6 KiB
Go
// Copyright (c) 2013 Conformal Systems LLC.
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"os/signal"
|
|
)
|
|
|
|
// interruptChannel is used to receive SIGINT (Ctrl+C) signals.
|
|
var interruptChannel chan os.Signal
|
|
|
|
// addHandlerChannel is used to add an interrupt handler to the list of handlers
|
|
// to be invoked on SIGINT (Ctrl+C) signals.
|
|
var addHandlerChannel = make(chan func())
|
|
|
|
// mainInterruptHandler listens for SIGINT (Ctrl+C) signals on the
|
|
// interruptChannel and invokes the registered interruptCallbacks accordingly.
|
|
// It also listens for callback registration. It must be run as a goroutine.
|
|
func mainInterruptHandler() {
|
|
// interruptCallbacks is a list of callbacks to invoke when a
|
|
// SIGINT (Ctrl+C) is received.
|
|
var interruptCallbacks []func()
|
|
|
|
for {
|
|
select {
|
|
case <-interruptChannel:
|
|
log.Infof("Received SIGINT (Ctrl+C). Shutting down...")
|
|
for _, callback := range interruptCallbacks {
|
|
callback()
|
|
}
|
|
|
|
// Signal the main goroutine to shutdown.
|
|
shutdownChannel <- true
|
|
|
|
case handler := <-addHandlerChannel:
|
|
interruptCallbacks = append(interruptCallbacks, handler)
|
|
}
|
|
}
|
|
}
|
|
|
|
// addInterruptHandler adds a handler to call when a SIGINT (Ctrl+C) is
|
|
// received.
|
|
func addInterruptHandler(handler func()) {
|
|
// Create the channel and start the main interrupt handler which invokes
|
|
// all other callbacks and exits if not already done.
|
|
if interruptChannel == nil {
|
|
interruptChannel = make(chan os.Signal, 1)
|
|
signal.Notify(interruptChannel, os.Interrupt)
|
|
go mainInterruptHandler()
|
|
}
|
|
|
|
addHandlerChannel <- handler
|
|
}
|