250

Ctrl+Cコンソールから送信された( SIGINT) シグナルをキャプチャし、部分的な実行合計を出力したいと考えています。

これはGolangで可能ですか?

注: 最初に質問を投稿したとき、私はCtrl+C代わりSIGTERMSIGINT.

4

10 に答える 10

309

os / signalパッケージを使用して、着信信号を処理できます。Ctrl+CSIGINTなので、これを使用してトラップできます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
    }
}()

プログラムを終了させて​​情報を印刷する方法は、完全にあなた次第です。

于 2012-06-29T21:16:17.557 に答える
29

他の回答に少し追加すると、実際に SIGTERM (kill コマンドによって送信されるデフォルトのシグナル) をキャッチしたい場合はsyscall.SIGTERM、os.Interrupt の代わりに使用できます。syscall インターフェイスはシステム固有のものであり、どこでも機能するとは限らないことに注意してください (例: Windows)。ただし、両方をキャッチするとうまく機能します。

c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
....
于 2013-05-14T08:08:34.777 に答える
23

上記の受け入れられた回答には(投稿時に)1つまたは2つの小さなタイプミスがあったため、クリーンアップされたバージョンを次に示します。この例では、Ctrl+を受け取ったときに CPU プロファイラーを停止していますC

// 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)                                                     
  }                                                                
}()    
于 2012-09-24T18:55:45.523 に答える
1

例を見てください

このプログラムを実行すると、シグナル待ちでブロックされます。ctrl-C (ターミナルでは ^C と表示されます) を入力すると、SIGINT シグナルを送信でき、プログラムは割り込みを出力して終了します。

信号。Notify は、指定されたチャネルを登録して、指定されたシグナルの通知を受信します。

package main

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

func main() {

    sig := make(chan os.Signal, 1)
    done := make(chan bool, 1)

    signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)

    go func() {
        sig := <-sig
        fmt.Println()
        fmt.Println(sig)
        done <- true

        fmt.Println("ctrl+c")
    }()

    fmt.Println("awaiting signal")
    <-done
    fmt.Println("exiting")
}

HTTPリクエストのキャンセルを検出



package main

import (
    "fmt"
    "net/http"
    "time"
)

func main() {

    mux := http.NewServeMux()
    mux.HandleFunc("/path", func(writer http.ResponseWriter, request *http.Request) {

        time.Sleep(time.Second * 5)

        select {
        case <-time.After(time.Millisecond * 10):

            fmt.Println("started")
            return
        case <-request.Context().Done():
            fmt.Println("canceled")
        }
    })

    http.ListenAndServe(":8000", mux)

}
于 2020-09-16T10:56:51.393 に答える
0

これは、クリーンアップするタスクがある場合に機能する別のバージョンです。コードは、メソッドにクリーンアップ プロセスを残します。

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
}

メイン関数をクリーンアップする必要がある場合は、go func() も使用してメインスレッドでシグナルをキャプチャする必要があります。

于 2017-11-20T00:52:29.897 に答える
0

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()
于 2017-07-09T17:59:15.760 に答える