main + daemon signal handlers
This commit changes the signal handler to be added once the command is executing. this is because the daemon has its own signal handler, that must try to shut down the node gracefully first. You know, just in case.
Juan Batiz-Benet committed
Nov 16, 2014 at 02:11 UTC
705465db8bd11627762c9e6bf09c49d098770f1e
2 files changed
+42
-24
cmd/ipfs2/daemon.go
+10
-18
@@ -3,9 +3,6 @@ package main
3
import (
4
"fmt"
5
"net/http"
6
- "os"
7
- "os/signal"
8
- "syscall"
6
7
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/net"
@@ -74,40 +71,35 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
71
ifpsHandler := &ipfsHandler{node}
72
mux.Handle("/ipfs/", ifpsHandler)
73
77
- err = listenAndServe(mux, host)
74
+ err = listenAndServe(node, mux, host)
75
return nil, err
76
}
77
81
-func listenAndServe(mux *http.ServeMux, host string) error {
78
+func listenAndServe(node *core.IpfsNode, mux *http.ServeMux, host string) error {
79
80
fmt.Printf("API server listening on '%s'\n", host)
81
s := manners.NewServer()
82
+
83
done := make(chan struct{}, 1)
84
defer func() {
85
done <- struct{}{}
86
}()
87
90
- // go wait until we kill it.
88
+ // go wait until the node dies
89
go func() {
92
- sig := sigTerm()
90
select {
91
+ case <-node.Closed():
92
case <-done:
95
- log.Info("daemon terminated at %s.", host)
96
- case <-sig:
97
- s.Shutdown <- true
98
- log.Info("terminating daemon at %s...", host)
93
+ return
94
}
95
+
96
+ log.Info("terminating daemon at %s...", host)
97
+ s.Shutdown <- true
98
}()
99
100
if err := s.ListenAndServe(host, mux); err != nil {
101
return err
102
}
105
- return nil
106
-}
103
108
-func sigTerm() chan os.Signal {
109
- sigc := make(chan os.Signal, 1)
110
- signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT,
111
- syscall.SIGTERM, syscall.SIGQUIT)
112
- return sigc
104
+ return nil
105
}
cmd/ipfs2/main.go
+32
-6
@@ -7,6 +7,7 @@ import (
7
"os"
8
"os/signal"
9
"runtime/pprof"
10
+ "syscall"
11
12
logging "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-logging"
13
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
@@ -124,7 +125,8 @@ func main() {
125
}
126
127
func (i *cmdInvocation) Run() (output io.Reader, err error) {
127
- handleInterrupt()
128
+ // setup our global interrupt handler.
129
+ i.setupInterruptHandler()
130
131
// check if user wants to debug. option OR env var.
132
debug, _, err := i.req.Option("debug").Bool()
@@ -281,6 +283,7 @@ func callCommand(req cmds.Request, root *cmds.Command) (cmds.Response, error) {
283
// this sets up the function that will initialize the node
284
// this is so that we can construct the node lazily.
285
ctx := req.Context()
286
+
287
ctx.ConstructNode = func() (*core.IpfsNode, error) {
288
cfg, err := ctx.GetConfig()
289
if err != nil {
@@ -442,14 +445,37 @@ func writeHeapProfileToFile() error {
445
}
446
447
// listen for and handle SIGTERM
445
-func handleInterrupt() {
446
- c := make(chan os.Signal, 1)
447
- signal.Notify(c, os.Interrupt)
448
+func (i *cmdInvocation) setupInterruptHandler() {
449
+
450
+ ctx := i.req.Context()
451
+ sig := allInterruptSignals()
452
453
go func() {
450
- for _ = range c {
451
- log.Info("Received interrupt signal, terminating...")
454
+
455
+ for {
456
+ // first time, try to shut down.
457
+ <-sig
458
+ log.Critical("Received interrupt signal, shutting down...")
459
+
460
+ n, err := ctx.GetNode()
461
+ if err == nil {
462
+ go n.Close()
463
+ select {
464
+ case <-n.Closed():
465
+ case <-sig:
466
+ log.Critical("Received another interrupt signal, terminating...")
467
+ }
468
+ }
469
+
470
os.Exit(0)
471
}
472
+
473
}()
474
}
475
+
476
+func allInterruptSignals() chan os.Signal {
477
+ sigc := make(chan os.Signal, 1)
478
+ signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT,
479
+ syscall.SIGTERM, syscall.SIGQUIT)
480
+ return sigc
481
+}