> Какие сигналы существуют в операционной системе (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Avito

Стек: Go

> Пример ответа

Короткий ответ

Сигналы - это асинхронные уведомления, которые ОС отправляет процессу для сообщения о событиях: завершении, ошибках, таймерах или пользовательских действиях. В POSIX-системах стандартный набор включает SIGINT, SIGTERM, SIGKILL, SIGHUP, SIGUSR1/2 и другие. В Go runtime перехватывает сигналы и транслирует их в канал os.Signal, позволяя приложению корректно завершиться или выполнить cleanup. Понимание сигналов критично для graceful shutdown и работы с процессами.

Подробное объяснение

Сигналы делятся на несколько категорий:

  • Управляющие терминалом: SIGINT (Ctrl+C), SIGQUIT (Ctrl+), SIGHUP (закрытие терминала)
  • Завершение: SIGTERM (стандартный запрос на завершение), SIGKILL (безусловное убийство), SIGSTOP/SIGCONT (пауза/возобновление)
  • Ошибки: SIGSEGV (нарушение памяти), SIGFPE (арифметическая ошибка), SIGPIPE (запись в закрытый pipe)
  • Пользовательские: SIGUSR1, SIGUSR2 - для межпроцессного взаимодействия
  • Таймеры: SIGALRM, SIGVTALRM, SIGPROF

Ключевые свойства:

  • Асинхронность: сигнал может прийти в любой момент выполнения
  • Обработка: default action, ignore, или пользовательский handler
  • Блокировка: сигнал можно временно заблокировать, но не отменить
  • Доставка: pending signals доставляются после разблокировки

В Go runtime:

  • Сигналы обрабатываются на уровне runtime, а не напрямую через syscall
  • signal.Notify(ch, sig...) регистрирует канал для получения сигналов
  • signal.Stop(ch) отменяет регистрацию
  • signal.Ignore(sig...) игнорирует сигналы
  • signal.Reset(sig...) возвращает default behavior

Особенности Go:

  • SIGKILL и SIGSTOP нельзя перехватить - это ограничение ОС
  • Go runtime сам обрабатывает SIGSEGV, SIGBUS и другие для panic
  • SIGPIPE по умолчанию вызывает завершение программы, но в Go это поведение изменено для stdout/stderr

На практике

Для backend-приложений на Go наиболее важны:

  1. Graceful shutdown: перехват SIGTERM и SIGINT для корректного завершения HTTP-сервера, закрытия соединений с БД, завершения in-flight запросов
  2. Reload конфигурации: SIGHUP часто используется для перезагрузки конфигов без остановки процесса
  3. Управление воркерами: SIGUSR1/SIGUSR2 для динамического изменения числа горутин или уровня логирования
  4. Дочерние процессы: необходимо пробрасывать сигналы в дочерние процессы и учитывать их статусы

Типичный паттерн graceful shutdown:

  • Создать канал для сигналов
  • Запустить HTTP-сервер в горутине
  • В main-горутине ждать сигнал
  • Вызвать server.Shutdown(ctx) с таймаутом

Пример кода

GO
package main
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
// Канал для сигналов
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
// HTTP-сервер
srv := &http.Server{Addr: ":8080"}
go func() {
fmt.Println("Server started")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
fmt.Printf("Server error: %v\n", err)
os.Exit(1)
}
}()
// Ожидание сигнала
sig := <-sigChan
fmt.Printf("Received signal: %v\n", sig)
// Graceful shutdown с таймаутом
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
fmt.Printf("Shutdown error: %v\n", err)
}
fmt.Println("Server stopped gracefully")
}

Как отвечать на собеседовании

Начни с определения сигналов как асинхронных уведомлений. Перечисли основные категории и приведи примеры для каждой. Обязательно упомяни разницу между SIGTERM и SIGKILL - это частый вопрос.

Затем переходи к Go-специфике: как runtime обрабатывает сигналы, зачем нужен signal.Notify, какие сигналы нельзя перехватить. Подчеркни практическую важность - graceful shutdown.

Если спросят про низкоуровневые детали, расскажи про блокировку сигналов, pending signals и разницу между обработкой в Go и C. Для senior-позиции важно показать понимание того, как сигналы взаимодействуют с планировщиком Go и горутинами.

Что проверяет интервьюер

  • Понимание базовой модели сигналов в POSIX
  • Знание конкретных сигналов и их назначения
  • Умение применять сигналы на практике (graceful shutdown)
  • Понимание особенностей обработки сигналов в Go runtime
  • Способность объяснить, почему SIGKILL нельзя перехватить
  • Понимание различий между сигналами и другими механизмами IPC

Типичные ошибки

  • Путаница между SIGTERM и SIGKILL: SIGTERM можно обработать, SIGKILL - нет
  • Забывают, что signal.Notify нужно вызывать до запуска сервера
  • Не используют буферизованный канал для сигналов - можно потерять сигнал
  • Пытаются перехватить SIGKILL или SIGSTOP
  • Не учитывают, что signal.Stop не закрывает канал
  • Путают signal.Ignore и signal.Reset
  • Не обрабатывают ошибку srv.Shutdown - игнорируют таймаут
  • Думают, что сигналы в Go работают так же, как в C - не учитывают особенности runtime

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью