Go by Example: Signals

A veces nos gustaría que nuestros programas en Go manejen inteligentemente las señales Unix. Por ejemplo, podríamos querer que un servidor se cierre de manera ordenada cuando recibe un SIGTERM, o que una herramienta de línea de comandos deje de procesar la entrada si recibe un SIGINT. Aquí está cómo manejar señales en Go con canales.

package main
import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
)
func main() {

La notificación de señales en Go funciona enviando valores de os.Signal en un canal. Crearemos un canal para recibir estas notificaciones. Note que este canal debe ser bufferizado.

    sigs := make(chan os.Signal, 1)

signal.Notify registra el canal dado para recibir notificaciones de las señales especificadas.

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

Podríamos recibir de sigs aquí en la función principal, pero veamos cómo esto también podría hacerse en una goroutine separada, para demostrar un escenario más realista de cierre ordenado.

    done := make(chan bool, 1)

Esta goroutine ejecuta una recepción bloqueante para señales. Cuando recibe una, la imprimirá y luego notificará al programa que puede terminar.

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

El programa esperará aquí hasta que reciba la señal esperada (como indica la goroutine anterior enviando un valor en done) y luego saldrá.

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

Cuando ejecutamos este programa, se bloqueará esperando una señal. Al escribir ctrl-C (que el terminal muestra como ^C), podemos enviar una señal SIGINT, haciendo que el programa imprima interrupt y luego salga.

$ go run signals.go
awaiting signal
^C
interrupt
exiting

Siguiente ejemplo: Exit.