mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-15 22:31:21 +00:00
Unclean shutdown on SIGINT / SIGTERM (#3308)
* libs/common: TrapSignal accepts logger as a first parameter and does not block anymore * previously it was dumping "captured ..." msg to os.Stdout * TrapSignal should not be responsible for blocking thread of execution Refs #3238 * exit with zero (0) code upon receiving SIGTERM/SIGINT Refs #3238 * fix formatting in docs/app-dev/abci-cli.md Co-Authored-By: melekes <anton.kalyaev@gmail.com> * fix formatting in docs/app-dev/abci-cli.md Co-Authored-By: melekes <anton.kalyaev@gmail.com>
This commit is contained in:
committed by
Ethan Buchman
parent
41f91318e9
commit
cdf3a74f48
@ -12,6 +12,9 @@ Special thanks to external contributors on this release:
|
|||||||
* Apps
|
* Apps
|
||||||
|
|
||||||
* Go API
|
* Go API
|
||||||
|
- [libs/common] TrapSignal accepts logger as a first parameter and does not block anymore
|
||||||
|
* previously it was dumping "captured ..." msg to os.Stdout
|
||||||
|
* TrapSignal should not be responsible for blocking thread of execution
|
||||||
|
|
||||||
* Blockchain Protocol
|
* Blockchain Protocol
|
||||||
|
|
||||||
@ -23,6 +26,7 @@ Special thanks to external contributors on this release:
|
|||||||
`/num_unconfirmed_txs` and `/unconfirmed_txs` RPC endpoints.
|
`/num_unconfirmed_txs` and `/unconfirmed_txs` RPC endpoints.
|
||||||
|
|
||||||
### IMPROVEMENTS:
|
### IMPROVEMENTS:
|
||||||
|
- [libs/common] \#3238 exit with zero (0) code upon receiving SIGTERM/SIGINT
|
||||||
|
|
||||||
### BUG FIXES:
|
### BUG FIXES:
|
||||||
|
|
||||||
|
@ -636,9 +636,7 @@ func cmdQuery(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func cmdCounter(cmd *cobra.Command, args []string) error {
|
func cmdCounter(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
app := counter.NewCounterApplication(flagSerial)
|
app := counter.NewCounterApplication(flagSerial)
|
||||||
|
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||||
|
|
||||||
// Start the listener
|
// Start the listener
|
||||||
@ -651,12 +649,14 @@ func cmdCounter(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait forever
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
cmn.TrapSignal(func() {
|
cmn.TrapSignal(logger, func() {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
srv.Stop()
|
srv.Stop()
|
||||||
})
|
})
|
||||||
return nil
|
|
||||||
|
// Run forever.
|
||||||
|
select {}
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdKVStore(cmd *cobra.Command, args []string) error {
|
func cmdKVStore(cmd *cobra.Command, args []string) error {
|
||||||
@ -681,12 +681,14 @@ func cmdKVStore(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait forever
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
cmn.TrapSignal(func() {
|
cmn.TrapSignal(logger, func() {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
srv.Stop()
|
srv.Stop()
|
||||||
})
|
})
|
||||||
return nil
|
|
||||||
|
// Run forever.
|
||||||
|
select {}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
|
@ -54,10 +54,14 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmn.TrapSignal(func() {
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
|
cmn.TrapSignal(logger, func() {
|
||||||
err := rs.Stop()
|
err := rs.Stop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Run forever.
|
||||||
|
select {}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,11 @@ func ensureAddrHasSchemeOrDefaultToTCP(addr string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runProxy(cmd *cobra.Command, args []string) error {
|
func runProxy(cmd *cobra.Command, args []string) error {
|
||||||
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
|
cmn.TrapSignal(logger, func() {
|
||||||
|
// TODO: close up shop
|
||||||
|
})
|
||||||
|
|
||||||
nodeAddr, err := ensureAddrHasSchemeOrDefaultToTCP(nodeAddr)
|
nodeAddr, err := ensureAddrHasSchemeOrDefaultToTCP(nodeAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -86,9 +91,6 @@ func runProxy(cmd *cobra.Command, args []string) error {
|
|||||||
return cmn.ErrorWrap(err, "starting proxy")
|
return cmn.ErrorWrap(err, "starting proxy")
|
||||||
}
|
}
|
||||||
|
|
||||||
cmn.TrapSignal(func() {
|
// Run forever
|
||||||
// TODO: close up shop
|
select {}
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,10 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
nm "github.com/tendermint/tendermint/node"
|
nm "github.com/tendermint/tendermint/node"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,25 +55,19 @@ func NewRunNodeCmd(nodeProvider nm.NodeProvider) *cobra.Command {
|
|||||||
return fmt.Errorf("Failed to create node: %v", err)
|
return fmt.Errorf("Failed to create node: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop upon receiving SIGTERM or CTRL-C
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
c := make(chan os.Signal, 1)
|
cmn.TrapSignal(logger, func() {
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
if n.IsRunning() {
|
||||||
go func() {
|
n.Stop()
|
||||||
for sig := range c {
|
|
||||||
logger.Error(fmt.Sprintf("captured %v, exiting...", sig))
|
|
||||||
if n.IsRunning() {
|
|
||||||
n.Stop()
|
|
||||||
}
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
if err := n.Start(); err != nil {
|
if err := n.Start(); err != nil {
|
||||||
return fmt.Errorf("Failed to start node: %v", err)
|
return fmt.Errorf("Failed to start node: %v", err)
|
||||||
}
|
}
|
||||||
logger.Info("Started node", "nodeInfo", n.Switch().NodeInfo())
|
logger.Info("Started node", "nodeInfo", n.Switch().NodeInfo())
|
||||||
|
|
||||||
// Run forever
|
// Run forever.
|
||||||
select {}
|
select {}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -89,12 +89,14 @@ func cmdKVStore(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait forever
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
cmn.TrapSignal(func() {
|
cmn.TrapSignal(logger, func() {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
srv.Stop()
|
srv.Stop()
|
||||||
})
|
})
|
||||||
return nil
|
|
||||||
|
// Run forever.
|
||||||
|
select {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -238,12 +240,14 @@ func cmdCounter(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait forever
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
cmn.TrapSignal(func() {
|
cmn.TrapSignal(logger, func() {
|
||||||
// Cleanup
|
// Cleanup
|
||||||
srv.Stop()
|
srv.Stop()
|
||||||
})
|
})
|
||||||
return nil
|
|
||||||
|
// Run forever.
|
||||||
|
select {}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -29,7 +29,21 @@ func parseFlags() (headPath string, chopSize int64, limitSize int64, version boo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fmtLogger struct{}
|
||||||
|
|
||||||
|
func (fmtLogger) Info(msg string, keyvals ...interface{}) {
|
||||||
|
strs := make([]string, len(keyvals))
|
||||||
|
for i, kv := range keyvals {
|
||||||
|
strs[i] = fmt.Sprintf("%v", kv)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s %s\n", msg, strings.Join(strs, ","))
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
|
cmn.TrapSignal(fmtLogger{}, func() {
|
||||||
|
fmt.Println("logjack shutting down")
|
||||||
|
})
|
||||||
|
|
||||||
// Read options
|
// Read options
|
||||||
headPath, chopSize, limitSize, version := parseFlags()
|
headPath, chopSize, limitSize, version := parseFlags()
|
||||||
@ -51,29 +65,22 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
// Forever read from stdin and write to AutoFile.
|
||||||
// Forever, read from stdin and write to AutoFile.
|
buf := make([]byte, readBufferSize)
|
||||||
buf := make([]byte, readBufferSize)
|
for {
|
||||||
for {
|
n, err := os.Stdin.Read(buf)
|
||||||
n, err := os.Stdin.Read(buf)
|
group.Write(buf[:n])
|
||||||
group.Write(buf[:n])
|
group.Flush()
|
||||||
group.Flush()
|
if err != nil {
|
||||||
if err != nil {
|
group.Stop()
|
||||||
group.Stop()
|
if err == io.EOF {
|
||||||
if err == io.EOF {
|
os.Exit(0)
|
||||||
os.Exit(0)
|
} else {
|
||||||
} else {
|
fmt.Println("logjack errored")
|
||||||
fmt.Println("logjack errored")
|
os.Exit(1)
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
|
|
||||||
// Trap signal
|
|
||||||
cmn.TrapSignal(func() {
|
|
||||||
fmt.Println("logjack shutting down")
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseBytesize(chopSize string) int64 {
|
func parseBytesize(chopSize string) int64 {
|
||||||
|
@ -34,21 +34,24 @@ func GoPath() string {
|
|||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrapSignal catches the SIGTERM and executes cb function. After that it exits
|
type logger interface {
|
||||||
// with code 1.
|
Info(msg string, keyvals ...interface{})
|
||||||
func TrapSignal(cb func()) {
|
}
|
||||||
|
|
||||||
|
// TrapSignal catches the SIGTERM/SIGINT and executes cb function. After that it exits
|
||||||
|
// with code 0.
|
||||||
|
func TrapSignal(logger logger, cb func()) {
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
go func() {
|
go func() {
|
||||||
for sig := range c {
|
for sig := range c {
|
||||||
fmt.Printf("captured %v, exiting...\n", sig)
|
logger.Info(fmt.Sprintf("captured %v, exiting...", sig))
|
||||||
if cb != nil {
|
if cb != nil {
|
||||||
cb()
|
cb()
|
||||||
}
|
}
|
||||||
os.Exit(1)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
select {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill the running process by sending itself SIGTERM.
|
// Kill the running process by sending itself SIGTERM.
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGoPath(t *testing.T) {
|
func TestOSGoPath(t *testing.T) {
|
||||||
// restore original gopath upon exit
|
// restore original gopath upon exit
|
||||||
path := os.Getenv("GOPATH")
|
path := os.Getenv("GOPATH")
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -28,7 +28,7 @@ func TestGoPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGoPathWithoutEnvVar(t *testing.T) {
|
func TestOSGoPathWithoutEnvVar(t *testing.T) {
|
||||||
// restore original gopath upon exit
|
// restore original gopath upon exit
|
||||||
path := os.Getenv("GOPATH")
|
path := os.Getenv("GOPATH")
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -24,17 +24,19 @@ type Result struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
mux := http.NewServeMux()
|
var (
|
||||||
cdc := amino.NewCodec()
|
mux = http.NewServeMux()
|
||||||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
cdc = amino.NewCodec()
|
||||||
|
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
|
||||||
|
)
|
||||||
|
|
||||||
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
|
cmn.TrapSignal(logger, func() {})
|
||||||
|
|
||||||
rpcserver.RegisterRPCFuncs(mux, routes, cdc, logger)
|
rpcserver.RegisterRPCFuncs(mux, routes, cdc, logger)
|
||||||
listener, err := rpcserver.Listen("0.0.0.0:8008", rpcserver.Config{})
|
listener, err := rpcserver.Listen("0.0.0.0:8008", rpcserver.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmn.Exit(err.Error())
|
cmn.Exit(err.Error())
|
||||||
}
|
}
|
||||||
go rpcserver.StartHTTPServer(listener, mux, logger)
|
rpcserver.StartHTTPServer(listener, mux, logger)
|
||||||
// Wait forever
|
|
||||||
cmn.TrapSignal(func() {
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,13 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-kit/kit/log/term"
|
"github.com/go-kit/kit/log/term"
|
||||||
|
|
||||||
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmrpc "github.com/tendermint/tendermint/rpc/client"
|
tmrpc "github.com/tendermint/tendermint/rpc/client"
|
||||||
)
|
)
|
||||||
@ -94,18 +93,12 @@ Examples:
|
|||||||
"broadcast_tx_"+broadcastTxMethod,
|
"broadcast_tx_"+broadcastTxMethod,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Quit when interrupted or received SIGTERM.
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
c := make(chan os.Signal, 1)
|
cmn.TrapSignal(logger, func() {
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
for _, t := range transacters {
|
||||||
go func() {
|
t.Stop()
|
||||||
for sig := range c {
|
|
||||||
fmt.Printf("captured %v, exiting...\n", sig)
|
|
||||||
for _, t := range transacters {
|
|
||||||
t.Stop()
|
|
||||||
}
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}()
|
})
|
||||||
|
|
||||||
// Wait until transacters have begun until we get the start time.
|
// Wait until transacters have begun until we get the start time.
|
||||||
timeStart := time.Now()
|
timeStart := time.Now()
|
||||||
|
@ -58,13 +58,17 @@ Examples:
|
|||||||
ton.Start()
|
ton.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
cmn.TrapSignal(func() {
|
// Stop upon receiving SIGTERM or CTRL-C.
|
||||||
|
cmn.TrapSignal(logger, func() {
|
||||||
if !noton {
|
if !noton {
|
||||||
ton.Stop()
|
ton.Stop()
|
||||||
}
|
}
|
||||||
monitor.Stop()
|
monitor.Stop()
|
||||||
listener.Close()
|
listener.Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Run forever.
|
||||||
|
select {}
|
||||||
}
|
}
|
||||||
|
|
||||||
func startMonitor(endpoints string) *monitor.Monitor {
|
func startMonitor(endpoints string) *monitor.Monitor {
|
||||||
|
Reference in New Issue
Block a user