Je veux capturer le Ctrl+C ( SIGINT
) envoyé par la console et d'imprimer des totaux partiels d'exécution.
Réponses
Trop de publicités?Lorsque nous lançons ce programme, il se bloque en attendant un signal. En tapant ctrl-C (que le terminal affiche comme ^C), nous pouvons envoyer un signal SIGINT, provoquant l'interruption du programme et sa sortie.
signal. Notify enregistre le canal donné pour recevoir les notifications des signaux spécifiés.
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")
}
détecter l'annulation d'une requête 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)
}
Vous pouvez avoir une goroutine différente qui détecte les signaux syscall.SIGINT et syscall.SIGTERM et les relaie à un canal en utilisant signal.Notifier . Vous pouvez envoyer un hook à cette goroutine en utilisant un canal et le sauvegarder dans une tranche de fonction. Lorsque le signal d'arrêt est détecté sur le canal, vous pouvez exécuter ces fonctions dans la tranche. Cela peut être utilisé pour nettoyer les ressources, attendre que les goroutines en cours d'exécution se terminent, persister les données ou imprimer les totaux d'exécution partielle.
J'ai écrit un petit utilitaire simple pour ajouter et exécuter des hooks à l'arrêt. J'espère qu'il pourra vous être utile.
https://github.com/ankit-arora/go-utils/blob/master/go-shutdown-hook/shutdown-hook.go
Vous pouvez le faire de manière différée.
exemple d'arrêt d'un serveur en douceur :
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()
Voici une autre version qui fonctionne si vous avez des tâches à nettoyer. Le code laissera le processus de nettoyage dans sa méthode.
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
}
dans le cas où vous devez nettoyer la fonction principale, vous devez capturer le signal dans le thread principal en utilisant aussi go func().
Décès est une bibliothèque simple qui utilise des canaux et un groupe d'attente pour attendre les signaux d'arrêt. Une fois que le signal a été reçu, elle appelle une méthode de fermeture sur toutes les structures que vous voulez nettoyer.
Juste pour mémoire, si quelqu'un a besoin d'un moyen de gérer les signaux sous Windows.
J'avais besoin de gérer un programme A qui appelait un programme B par le biais de os/exec, mais le programme B n'a jamais été en mesure de se terminer gracieusement car l'envoi de signaux par le biais de cmd.Process.Signal(syscall.SIGTERM)
ou d'autres signaux ne sont pas pris en charge par Windows.
J'ai traité ce problème en créant un fichier temporaire comme signal. Par exemple, le programme A crée le fichier .signal.term
et le programme B doit vérifier si ce fichier existe sur la base d'intervalle. Si le fichier existe, il quittera le programme et effectuera un nettoyage si nécessaire.
Je suis sûr qu'il y a d'autres moyens, mais celui-ci a fait l'affaire.
- Réponses précédentes
- Plus de réponses