Programming

"지연"방식으로 Ctrl + C 신호를 캡처하고 정리 기능을 실행할 수 있습니까?

procodes 2020. 5. 16. 11:21
반응형

"지연"방식으로 Ctrl + C 신호를 캡처하고 정리 기능을 실행할 수 있습니까?


콘솔에서 보낸 Ctrl+C( SIGINT) 신호 를 캡처하고 부분 실행 합계를 인쇄하고 싶습니다 .

골랑에서 가능합니까?

참고 : 내가 먼저 질문을 게시 할 때 나는에 대해 혼란스러워했다 Ctrl+C되는 SIGTERM대신 SIGINT.


os / signal 패키지를 사용하여 들어오는 신호를 처리 할 수 있습니다 . ^ 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
    }
}()

프로그램을 종료하고 정보를 인쇄하는 방식은 전적으로 귀하에게 달려 있습니다.


이것은 작동합니다 :

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
    }
}

다른 답변에 약간 더하기 위해 실제로 SIGTERM (kill 명령으로 전송 된 기본 신호)을 잡으려면 syscall.SIGTERMos.Interrupt 대신 사용할 수 있습니다 . syscall 인터페이스는 시스템에 따라 다르며 모든 곳에서 작동하지 않을 수 있습니다 (예 : Windows). 그러나 두 가지를 모두 잘 잡을 수 있습니다.

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

위에 게시 된 답변에 하나 또는 두 개의 작은 오타가 있었으므로 여기에 정리 된 버전이 있습니다. 이 예제에서는 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)                                                     
  }                                                                
}()    

위의 모든 내용은 접속했을 때 작동하는 것처럼 보이지만 gobyexample의 신호 페이지 에는 신호를 캡처하는 데 대한 깨끗하고 완전한 예가 있습니다. 이 목록에 추가 할 가치가 있습니다.


이것은 정리해야 할 작업이있는 경우 사용할 수있는 다른 버전입니다. 코드는 방법에 따라 정리 프로세스를 유지합니다.

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
}

in case you need to clean main function you need to capture signal in main thread using go func() as well.


Death is a simple library that uses channels and a wait group to wait for shutdown signals. Once the signal has been received it will then call a close method on all of your structs that you want to cleanup.


You can have a different goroutine that detects syscall.SIGINT and syscall.SIGTERM signals and relay them to a channel using signal.Notify. You can send a hook to that goroutine using a channel and save it in a function slice. When the shutdown signal is detected on the channel, you can execute those functions in the slice. This can be used to clean up the resources, wait for running goroutines to finish, persist data, or print partial run totals.

I wrote a small and simple utility to add and run hooks at shutdown. Hope it can be of help.

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

You can do this in a 'defer' fashion.

example for shutting down a server gracefully :

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()

Just for the record if somebody needs a way to handle signals on Windows. I had a requirement to handle from prog A calling prog B through os/exec but prog B never was able to terminate gracefully because sending signals through ex. cmd.Process.Signal(syscall.SIGTERM) or other signals are not supported on Windows. The way I handled is by creating a temp file as a signal ex. .signal.term through prog A and prog B needs to check if that file exists on interval base, if file exists it will exit the program and handle a cleanup if needed, I'm sure there are other ways but this did the job.

참고URL : https://stackoverflow.com/questions/11268943/is-it-possible-to-capture-a-ctrlc-signal-and-run-a-cleanup-function-in-a-defe

반응형