Go за Прикладом: Сигнали

Інколи виникає необхідність реагувати на Сигнали операційної системи (Unix)) не так, як задумано. Це буває корисно наприклад у випадках, коли потрібно щоб сервер обережно завершив свою роботу по отриманні сигналу SIGTERM, або програма що працює з командним рядком зупинили обробку вводу - по отриманніSIGINT.

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

Нотифікації сигналів у Go працюють за допомогою передачі значення os.Signal через канал. Ми створимо канал для отримання таких повідомлень, ми також створимо ще один канал для повідомлення про завершення програми.

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

signal.Notify реєструє зазначений канал для отримання повідомлень переданих сигналів. Як тільки таккий сигнал буде зареєстровано - він буде переданий в канал.

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

Ми можемо отримувати від sigs, але давайте розглянемо як це можливо реалізувати в окремій горутині, для демонстрації більш реалістичного сценарію елегантного виходу.

    done := make(chan bool, 1)

Ця горутинка - виконає блокування поки не буде отримано сигнал з каналу. Як тільки такий сигнал буде їй передано - вона виведе повідомлення і повідомить програму, що їй пора завершуватись.

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

Програма чекатиме тут допоки вона не отримає очікуваний сигнал (як визначено горутинкою вище - що має надіслати в done значення), після чого вона завершить роботу.

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

Як тільки ми запустимо цю програму вона “заблокується” і буде очікувати сигнал. Натискаючи ctrl-C (який показано тут як ^C) ми передамо сигнал SIGINT, що змусить програму надрукувати interrupt і завершити роботу.

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

Наступний приклад: Exit.