for example signals go sigterm

signals - example - ¿Es posible capturar una señal Ctrl+C y ejecutar una función de limpieza, de forma "diferida"?



sigterm example (9)

Esta es otra versión que funciona en caso de que tenga algunas tareas para limpiar. El código dejará el proceso de limpieza en su método.

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 }

en caso de que necesite limpiar la función principal, necesita capturar la señal en el hilo principal con go func () también.

Quiero capturar la señal Ctrl + C ( SIGINT ) enviada desde la consola e imprimir algunos totales de ejecución parcial.

¿Es esto posible en Golang?

Nota: Cuando publiqué la pregunta por primera vez, me confundí cuando Ctrl + C era SIGTERM lugar de SIGINT .


Esto funciona:

package main import ( "fmt" "os" "os/signal" "syscall" "time" // or "runtime" ) func cleanup() { fmt.Println("cleanup") } func main() { c := make(chan os.Signal, 2) 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 } }


Hubo (en el momento de la publicación) uno o dos pequeños errores tipográficos en la respuesta aceptada anteriormente, así que aquí está la versión limpia. En este ejemplo, estoy deteniendo el perfilador de la CPU cuando recibo Ctrl + 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) } }()


Para agregar algo a las otras respuestas, si realmente desea capturar SIGTERM (la señal predeterminada enviada por el comando kill), puede usar syscall.SIGTERM en lugar de os.Interrupt. Tenga en cuenta que la interfaz de syscall es específica del sistema y puede que no funcione en todas partes (por ejemplo, en Windows). Pero funciona bien para atrapar ambos:

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


Puede tener una rutina diferente que detecte las señales syscall.SIGINT y syscall.SIGTERM y las retransmita a un canal utilizando documentation . Puede enviar un gancho a esa goroutine usando un canal y guardarlo en un corte de función. Cuando se detecta la señal de apagado en el canal, puede ejecutar esas funciones en el corte. Esto se puede usar para limpiar los recursos, esperar que los goroutines en ejecución terminen, persistan datos o impriman totales de ejecución parcial.

Escribí una utilidad pequeña y simple para agregar y ejecutar ganchos en el cierre. Espero que pueda ser de ayuda.

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

Puedes hacer esto de una manera ''diferida''.

ejemplo para cerrar un servidor con gracia:

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


Puede usar el paquete os/signal para manejar las señales entrantes. ^ C es SIGINT , por lo que puede usar esto para atrapar 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 } }()

La manera en la que hace que su programa finalice e imprima información depende exclusivamente de usted.


Solo para el registro si alguien necesita una forma de manejar señales en Windows. Tenía un requerimiento para manejar desde el prog A prog progresivo B a través de os / exec pero el prog B nunca fue capaz de terminar con gracia porque el envío de señales a través de ej. cmd.Process.Signal (syscall.SIGTERM) u otras señales no son compatibles con Windows. La forma en que manejo es creando un archivo temporal como una señal ex. .signal.term a través del programa A y el programa B necesita verificar si ese archivo existe en la base de intervalos, si existe el archivo saldrá del programa y se encargará de una limpieza, de ser necesario, estoy seguro de que hay otras formas, pero esto funcionó.


Todo lo anterior parece funcionar cuando se empalma, pero la página de señales de gobyexample tiene un ejemplo realmente limpio y completo de captura de señal. Vale la pena agregar a esta lista.


Death es una biblioteca simple que usa canales y un grupo de espera para esperar las señales de apagado. Una vez que la señal ha sido recibida, llamará a un método de cierre en todas sus estructuras que desea limpiar.