Какие существуют виды контекстов в Go и в чем их различия?

Ответ

Пакет context в Go предназначен для управления отменой операций, установкой дедлайнов и передачей данных, специфичных для запроса, через границы API и между горутинами.

Существует несколько основных способов создания и использования контекстов:

  1. context.Background() — это корневой, пустой контекст. Он никогда не отменяется, не имеет значений и дедлайнов. Обычно используется в main(), при инициализации или в тестах как отправная точка для создания других контекстов.

    ctx := context.Background()
  2. context.TODO() — также пустой контекст, который следует использовать, когда вы не уверены, какой контекст применить, или если функция будет доработана для его получения в будущем. Служит как временная "заглушка".

    ctx := context.TODO()
  3. context.WithCancel(parent) — создает дочерний контекст, который можно отменить вручную. Возвращает контекст и функцию cancel(). Вызов этой функции отменяет данный контекст и все производные от него.

    ctx, cancel := context.WithCancel(context.Background())
    defer cancel() // Важно всегда вызывать cancel, чтобы освободить ресурсы
  4. context.WithTimeout(parent, timeout) — создает контекст, который автоматически отменяется по истечении заданного timeout.

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
  5. context.WithDeadline(parent, time) — похож на WithTimeout, но отмена происходит в конкретный момент времени (time), а не через интервал.

    deadline := time.Now().Add(2 * time.Hour)
    ctx, cancel := context.WithDeadline(context.Background(), deadline)
    defer cancel()
  6. context.WithValue(parent, key, value) — позволяет передавать данные внутри контекста. Важно: этот способ следует использовать с осторожностью, в основном для передачи опциональных, сквозных данных (например, ID трассировки, токен аутентификации), а не обязательных параметров функции, так как это делает API неявным.

    type key string
    const userIDKey key = "userID"
    ctx := context.WithValue(context.Background(), userIDKey, 123)