diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index b2104ce6f..56d0dc811 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -80,6 +80,15 @@ func daemonFunc(req cmds.Request, res cmds.Response) { // let the user know we're going. fmt.Printf("Initializing daemon...\n") + ctx := req.Context() + + go func() { + select { + case <-ctx.Context.Done(): + fmt.Println("Received interrupt signal, shutting down...") + } + }() + // first, whether user has provided the initialization flag. we may be // running in an uninitialized state. initialize, _, err := req.Option(initOptionKwd).Bool() @@ -111,7 +120,6 @@ func daemonFunc(req cmds.Request, res cmds.Response) { return } - ctx := req.Context() cfg, err := ctx.GetConfig() if err != nil { res.SetError(err, cmds.ErrNormal) @@ -149,7 +157,19 @@ func daemonFunc(req cmds.Request, res cmds.Response) { res.SetError(err, cmds.ErrNormal) return } - defer node.Close() + + defer func() { + // We wait for the node to close first, as the node has children + // that it will wait for before closing, such as the API server. + node.Close() + + select { + case <-ctx.Context.Done(): + log.Info("Gracefully shut down daemon") + default: + } + }() + req.Context().ConstructNode = func() (*core.IpfsNode, error) { return node, nil } diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index 21ec9b937..4b69e77f8 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -141,8 +141,9 @@ func main() { } // ok, finally, run the command invocation. - intrh := invoc.SetupInterruptHandler() + intrh, ctx := invoc.SetupInterruptHandler(ctx) defer intrh.Close() + output, err := invoc.Run(ctx) if err != nil { printErr(err) @@ -514,14 +515,15 @@ func (ih *IntrHandler) Handle(handler func(count int, ih *IntrHandler), sigs ... }() } -func (i *cmdInvocation) SetupInterruptHandler() io.Closer { +func (i *cmdInvocation) SetupInterruptHandler(ctx context.Context) (io.Closer, context.Context) { intrh := NewIntrHandler() + ctx, cancelFunc := context.WithCancel(ctx) + handlerFunc := func(count int, ih *IntrHandler) { switch count { case 1: - // first time, try to shut down - fmt.Println("Received interrupt signal, shutting down...") + fmt.Println() // Prevent un-terminated ^C character in terminal ctx := i.req.Context() @@ -535,16 +537,7 @@ func (i *cmdInvocation) SetupInterruptHandler() io.Closer { ih.wg.Add(1) go func() { defer ih.wg.Done() - - // TODO cancel the command context instead - n, err := ctx.GetNode() - if err != nil { - log.Error(err) - os.Exit(-1) - } - - n.Close() - log.Info("Gracefully shut down.") + cancelFunc() }() default: @@ -555,7 +548,7 @@ func (i *cmdInvocation) SetupInterruptHandler() io.Closer { intrh.Handle(handlerFunc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) - return intrh + return intrh, ctx } func profileIfEnabled() (func(), error) {