Функция signal.NotifyContext

Функция signal.NotifyContext создает новый контекст, который будет автоматически отменен при получении одного из указанных сигналов. Она принимает родительский контекст и набор сигналов OS, на которые нужно реагировать. Функция возвращает новый контекст и функцию остановки, которая прекращает отслеживание сигналов и возвращает контекст в исходное состояние.

Синтаксис

gosignal.NotifyContext(ctx context.Context, sig ...os.Signal) (context.Context, context.CancelFunc)

Пример

Создадим контекст, который будет отменен при получении сигнала SIGTERM или SIGINT, и запустим горутину для обработки отмены:

gopackage main

import (
  "context"
  "fmt"
  "os"
  "os/signal"
  "syscall"
  "time"
)

func main() {
  ctx, stop := signal.NotifyContext(
    context.Background(),
    syscall.SIGTERM,
    syscall.SIGINT,
  )
  defer stop()

  <-ctx.Done()
  fmt.Println("ctx.Done called")
}

Результат выполнения кода при получении сигнала:

go"ctx.Done called"

Пример

Используем функцию остановки для прекращения отслеживания сигналов до их получения:

gopackage main

import (
  "context"
  "fmt"
  "os"
  "os/signal"
  "syscall"
  "time"
)

func main() {
  ctx, stop := signal.NotifyContext(
    context.Background(),
    syscall.SIGTERM,
  )
  
  stop()
  
  select {
  case <-ctx.Done():
    fmt.Println("ctx.Done called")
  case <-time.After(100 * time.Millisecond):
    fmt.Println("ctx.Done not called")
  }
}

Результат выполнения кода:

go"ctx.Done not called"

Пример

Обработаем несколько сигналов в цикле с использованием контекста и канала для уведомлений:

gopackage main

import (
  "context"
  "fmt"
  "os"
  "os/signal"
  "syscall"
  "time"
)

func main() {
  ctx, stop := signal.NotifyContext(
    context.Background(),
    syscall.SIGUSR1,
    syscall.SIGUSR2,
  )
  defer stop()

  sigChan := make(chan os.Signal, 1)
  signal.Notify(sigChan, syscall.SIGUSR1, syscall.SIGUSR2)

  for {
    select {
    case sig := <-sigChan:
      fmt.Printf("ctx.Done not called, signal: %s", sig)
    case <-ctx.Done():
      fmt.Println("ctx.Done called")
      return
    case <-time.After(5 * time.Second):
      fmt.Println("timeout")
      return
    }
  }
}

Результат выполнения кода при получении сигнала:

go"ctx.Done not called, signal: user defined signal 1"

Смотрите также

  • функцию signal.Notify,
    которая отправляет уведомления о сигналах в канал
  • функцию signal.Stop,
    которая останавливает доставку сигналов в канал
  • функцию signal.Ignore,
    которая игнорирует указанные сигналы
  • функцию signal.Reset,
    которая восстанавливает обработку сигналов по умолчанию