是否有可能捕获按Ctrl + C信号,并在“延迟”的方式运行清理功能,?是否有可能捕获按Ctrl +

2019-05-12 15:01发布

我想捕捉按Ctrl + C( SIGINT从控制台发送)信号,并打印出一些偏运行总计。

这是可能的Golang?

注:当我第一次发布我感到困惑按Ctrl + C是问题SIGTERM而不是SIGINT

Answer 1:

您可以使用OS /信号包来处理输入信号。 ^ C是SIGINT ,所以你可以使用这个陷阱os.Interrupt

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func(){
    for sig := range c {
        // sig is a ^C, handle it
    }
}()

该方式中,你会导致程序终止,并打印信息是完全取决于你。



Answer 2:

这工作:

package main

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
    "time" // or "runtime"
)

func cleanup() {
    fmt.Println("cleanup")
}

func main() {
    c := make(chan os.Signal)
    signal.Notify(c, os.Interrupt, syscall.SIGTERM)
    go func() {
        <-c
        cleanup()
        os.Exit(1)
    }()

    for {
        fmt.Println("sleeping...")
        time.Sleep(10 * time.Second) // or runtime.Gosched() or similar per @misterbee
    }
}


Answer 3:

稍微添加到其他的答案,如果你真的想赶上SIGTERM(由kill命令发送的缺省信号),你可以使用syscall.SIGTERM到位os.Interrupt的。 要注意的是系统调用接口是系统特定的,可能不会(在Windows EG)工作无处不在。 但它很好地赶上两个:

c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
....


Answer 4:

有(以发帖时间)一个或以上的接受的答案两个小错别字,所以这里的清理版本。 在这个例子中接收按Ctrl + C,当我停止CPU分析器。

// capture ctrl+c and stop CPU profiler                            
c := make(chan os.Signal, 1)                                       
signal.Notify(c, os.Interrupt)                                     
go func() {                                                        
  for sig := range c {                                             
    log.Printf("captured %v, stopping profiler and exiting..", sig)
    pprof.StopCPUProfile()                                         
    os.Exit(1)                                                     
  }                                                                
}()    


Answer 5:

上述所有的看起来拼接时的工作,但gobyexample的信号页面具有信号捕捉的很干净,完整的例子。 值得加入到这个列表。



Answer 6:

这是另外一种在你有一些任务来清理情况工作版本。 代码将留在他们的方法清理过程。

package main

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"

)



func main() {

    _,done1:=doSomething1()
    _,done2:=doSomething2()

    //do main thread


    println("wait for finish")
    <-done1
    <-done2
    fmt.Print("clean up done, can exit safely")

}

func doSomething1() (error, chan bool) {
    //do something
    done:=make(chan bool)
    c := make(chan os.Signal, 2)
    signal.Notify(c, os.Interrupt, syscall.SIGTERM)
    go func() {
        <-c
        //cleanup of something1
        done<-true
    }()
    return nil,done
}


func doSomething2() (error, chan bool) {
    //do something
    done:=make(chan bool)
    c := make(chan os.Signal, 2)
    signal.Notify(c, os.Interrupt, syscall.SIGTERM)
    go func() {
        <-c
        //cleanup of something2
        done<-true
    }()
    return nil,done
}

如果你需要清理的主要功能则需要使用去FUNC(在主线程捕捉到信号),以及。



Answer 7:

死亡是一种使用信道和一个等待组等待关闭信号一个简单的库。 一旦信号被接收,将然后调用要清理在所有结构的close方法。



Answer 8:

你可以有一个不同的goroutine检测syscall.SIGINT和syscall.SIGTERM信号,并将其传递给使用通道signal.Notify 。 您可以使用一个通道发送钩到够程,并将其保存在函数切片。 当通道上检测到关机信号,则可以在片执行这些功能。 这可以用来清理资源,等待运行够程完成,持久化数据,或打印部分运行总计。

我写了一个小而简单的工具来添加和关机时运行的钩子。 希望能有所帮助。

https://github.com/ankit-arora/go-utils/blob/master/go-shutdown-hook/shutdown-hook.go

您可以在“延迟”的方式做到这一点。

例如,对于正常关闭服务器:

srv := &http.Server{}

go_shutdown_hook.ADD(func() {
    log.Println("shutting down server")
    srv.Shutdown(nil)
    log.Println("shutting down server-done")
})

l, err := net.Listen("tcp", ":3090")

log.Println(srv.Serve(l))

go_shutdown_hook.Wait()


Answer 9:

只是为了记录,如果有人需要一种方式来处理Windows的信号。 我有一个要求,从通过OS / EXEC但前卫乙PROG主叫PROG B到处理从来就没有能够正常终止,因为通过前发送信号。 cmd.Process.Signal(syscall.SIGTERM)或其他信号不支持Windows。 我处理的方法是通过创建一个临时文件作为信号前。 .signal.term通过PROG A和PROG B需要检查该文件是否存在区间的基础上,如果文件存在,它将退出程序和处理如果需要的话,我敢肯定还有其他的方法,但这种做的工作清理。



文章来源: Is it possible to capture a Ctrl+C signal and run a cleanup function, in a “defer” fashion?