提交 cf6a268c 作者: Tor Arne Vestbø 提交者: Tor Arne Vestbø

Handle ipfs command interruption by cancelling the command context

Instead of assuming the command is the daemon command and closing
the node, which resulted in bugs like #1053, we cancel the context
and let the context children detect the cancellation and gracefully
clean up after themselves.

The shutdown logging has been moved into the daemon command, where
it makes more sense, so that commands like ping will not print out
the same output on cancellation.
上级 cc45e21e
...@@ -80,6 +80,15 @@ func daemonFunc(req cmds.Request, res cmds.Response) { ...@@ -80,6 +80,15 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
// let the user know we're going. // let the user know we're going.
fmt.Printf("Initializing daemon...\n") 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 // first, whether user has provided the initialization flag. we may be
// running in an uninitialized state. // running in an uninitialized state.
initialize, _, err := req.Option(initOptionKwd).Bool() initialize, _, err := req.Option(initOptionKwd).Bool()
...@@ -111,7 +120,6 @@ func daemonFunc(req cmds.Request, res cmds.Response) { ...@@ -111,7 +120,6 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
return return
} }
ctx := req.Context()
cfg, err := ctx.GetConfig() cfg, err := ctx.GetConfig()
if err != nil { if err != nil {
res.SetError(err, cmds.ErrNormal) res.SetError(err, cmds.ErrNormal)
...@@ -149,7 +157,19 @@ func daemonFunc(req cmds.Request, res cmds.Response) { ...@@ -149,7 +157,19 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
res.SetError(err, cmds.ErrNormal) res.SetError(err, cmds.ErrNormal)
return 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) { req.Context().ConstructNode = func() (*core.IpfsNode, error) {
return node, nil return node, nil
} }
......
...@@ -141,8 +141,9 @@ func main() { ...@@ -141,8 +141,9 @@ func main() {
} }
// ok, finally, run the command invocation. // ok, finally, run the command invocation.
intrh := invoc.SetupInterruptHandler() intrh, ctx := invoc.SetupInterruptHandler(ctx)
defer intrh.Close() defer intrh.Close()
output, err := invoc.Run(ctx) output, err := invoc.Run(ctx)
if err != nil { if err != nil {
printErr(err) printErr(err)
...@@ -514,14 +515,15 @@ func (ih *IntrHandler) Handle(handler func(count int, ih *IntrHandler), sigs ... ...@@ -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() intrh := NewIntrHandler()
ctx, cancelFunc := context.WithCancel(ctx)
handlerFunc := func(count int, ih *IntrHandler) { handlerFunc := func(count int, ih *IntrHandler) {
switch count { switch count {
case 1: case 1:
// first time, try to shut down fmt.Println() // Prevent un-terminated ^C character in terminal
fmt.Println("Received interrupt signal, shutting down...")
ctx := i.req.Context() ctx := i.req.Context()
...@@ -535,16 +537,7 @@ func (i *cmdInvocation) SetupInterruptHandler() io.Closer { ...@@ -535,16 +537,7 @@ func (i *cmdInvocation) SetupInterruptHandler() io.Closer {
ih.wg.Add(1) ih.wg.Add(1)
go func() { go func() {
defer ih.wg.Done() defer ih.wg.Done()
cancelFunc()
// 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.")
}() }()
default: default:
...@@ -555,7 +548,7 @@ func (i *cmdInvocation) SetupInterruptHandler() io.Closer { ...@@ -555,7 +548,7 @@ func (i *cmdInvocation) SetupInterruptHandler() io.Closer {
intrh.Handle(handlerFunc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM) intrh.Handle(handlerFunc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
return intrh return intrh, ctx
} }
func profileIfEnabled() (func(), error) { func profileIfEnabled() (func(), error) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论