Обработка Unix-сигналов в Go

GolangGolangBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

Лаборатория Сигналов демонстрирует, как обрабатывать Unix-сигналы в программах на Go с использованием каналов.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("Golang")) -.-> go/NetworkingGroup(["Networking"]) go/NetworkingGroup -.-> go/signals("Signals") subgraph Lab Skills go/signals -.-> lab-15505{{"Обработка Unix-сигналов в Go"}} end

Сигналы

В некоторых случаях мы хотим, чтобы наши программы на Go умело обрабатывали Unix-сигналы. Например, мы можем захотеть, чтобы сервер прекращал работу gracefully, когда получает SIGTERM, или чтобы командная строка прекращала обрабатывать ввод, если получает SIGINT.

  • Создайте буферизованный канал для приема уведомлений о os.Signal.
  • Зарегистрируйте канал для приема уведомлений о заданных сигналах с использованием signal.Notify.
  • Создайте goroutine для выполнения блокирующего приема сигналов.
  • Выведите полученный сигнал и уведомите программу о том, что она может завершиться.
  • Подождите ожидаемый сигнал и затем выйдите.
## Когда мы запускаем эту программу, она будет заблокирована, ожидая сигнала.
## Нажав `ctrl-C` (что в терминале отображается как `^C`), мы можем отправить сигнал `SIGINT`,
## что вызовет вывод программы `interrupt` и затем выход.
$ go run signals.go
awaiting signal
^C
interrupt
exiting

Ниже представлен полный код:

// Иногда мы хотим, чтобы наша программа на Go умело обрабатывала
// [Unix-сигналы](https://en.wikipedia.org/wiki/Unix_signal).
// Например, мы можем захотеть, чтобы сервер прекращал работу gracefully,
// когда получает `SIGTERM`, или чтобы командная строка прекращала обрабатывать ввод,
// если получает `SIGINT`. Вот, как обрабатывать сигналы в Go с использованием каналов.

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` здесь в основной функции,
	// но давайте посмотрим, как это можно сделать в отдельной goroutine,
	// чтобы продемонстрировать более реалистичную ситуацию graceful shutdown.
	done := make(chan bool, 1)

	go func() {
		// Эта goroutine выполняет блокирующий прием сигналов.
		// Когда она получает сигнал, она выводит его и затем уведомляет программу
		// о том, что она может завершиться.
		sig := <-sigs
		fmt.Println()
		fmt.Println(sig)
		done <- true
	}()

	// Программа будет ждать здесь, пока не получит ожидаемый сигнал
	// (как показано выше, когда goroutine отправляет значение по `done`),
	// а затем выйдет.
	fmt.Println("awaiting signal")
	<-done
	fmt.Println("exiting")
}

Резюме

Лаборатория Сигналов демонстрирует, как обрабатывать Unix-сигналы в программах на Go с использованием каналов. Создав буферизованный канал для приема уведомлений о os.Signal и зарегистрировав канал для приема уведомлений о заданных сигналах с использованием signal.Notify, мы можем优雅но обрабатывать сигналы и выходить из программы, когда получаем ожидаемый сигнал.