Skip to content

Commit

Permalink
Improve shutdown listener.
Browse files Browse the repository at this point in the history
Copy shutdown listener logic from dcrd to:
  - improve OS signal handling.
  - add logging when a signal is received so it is clear why the process
    is being shutdown.
  • Loading branch information
jholdstock committed Oct 2, 2023
1 parent 5fb2258 commit c3559bf
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 11 deletions.
13 changes: 2 additions & 11 deletions decred.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ import (
"net"
"net/netip"
"os"
"os/signal"
"path/filepath"
"sync"
"syscall"
"time"

"github.com/decred/dcrd/chaincfg/v3"
Expand Down Expand Up @@ -138,6 +136,8 @@ func creep(ctx context.Context, netParams *chaincfg.Params) {
}

func main() {
ctx := shutdownListener()

cfg, err := loadConfig()
if err != nil {
fmt.Fprintf(os.Stderr, "loadConfig: %v\n", err)
Expand All @@ -158,15 +158,6 @@ func main() {
}
amgr.AddAddresses([]netip.AddrPort{seeder})

ctx, shutdown := context.WithCancel(context.Background())
killSwitch := make(chan os.Signal, 1)
signal.Notify(killSwitch, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
go func() {
<-killSwitch
log.Print("Shutting down...")
shutdown()
}()

var wg sync.WaitGroup
wg.Add(1)
go func() {
Expand Down
43 changes: 43 additions & 0 deletions signal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2015-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
"context"
"log"
"os"
"os/signal"
)

// interruptSignals defines the default signals to catch in order to do a proper
// shutdown. This may be modified during init depending on the platform.
var interruptSignals = []os.Signal{os.Interrupt}

// shutdownListener returns a context whose done channel will be closed when OS
// signals such as SIGINT (Ctrl+C) are received.
func shutdownListener() context.Context {
ctx, cancel := context.WithCancel(context.Background())
go func() {
interruptChannel := make(chan os.Signal, 1)
signal.Notify(interruptChannel, interruptSignals...)

// Listen for initial shutdown signal and cancel the context.
select {
case sig := <-interruptChannel:
log.Printf("Received signal (%s). Shutting down...", sig)
cancel()
case <-ctx.Done():
}

// Listen for repeated signals and display a message so the user knows
// the shutdown is in progress and the process is not hung.
for {
sig := <-interruptChannel
log.Printf("Received signal (%s). Already shutting down...", sig)
}
}()

return ctx
}
15 changes: 15 additions & 0 deletions signal_syscall.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2021-2023 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
//
//go:build windows || aix || android || darwin || dragonfly || freebsd || hurd || illumos || ios || linux || netbsd || openbsd || solaris

package main

import (
"syscall"
)

func init() {
interruptSignals = append(interruptSignals, syscall.SIGTERM, syscall.SIGHUP)
}

0 comments on commit c3559bf

Please sign in to comment.