Функция context.WithTimeout

Функция context.WithTimeout создает новый контекст с таймаутом. Она принимает родительский контекст и продолжительность времени, после которого контекст будет автоматически отменен. Функция возвращает новый контекст и функцию отмены. Если таймаут истекает, контекст завершается с ошибкой context.DeadlineExceeded.

Синтаксис

goctx, cancel := context.WithTimeout(parent, timeout)
defer cancel()

Первый параметр parent — родительский контекст, от которого наследуется новый контекст. Второй параметр timeout — время в наносекундах, через которое контекст будет отменен. Возвращаемое значение — новый контекст и функция для ручной отмены.

Пример использования с таймаутом

Давайте создадим контекст с таймаутом в 1 секунду и выполним операцию, которая занимает больше времени:

gopackage main

import (
  "context"
  "fmt"
  "time"
)

func main() {
  ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
  defer cancel()

  select {
  case <-time.After(2 * time.Second):
    fmt.Println("operation completed")
  case <-ctx.Done():
    fmt.Println(ctx.Err())
  }
}

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

go"context deadline exceeded"

В этом примере контекст отменяется через 1 секунду, поэтому операция не успевает завершиться и выводится ошибка превышения времени.

Пример с успешным завершением

Теперь давайте выполним операцию, которая укладывается в установленный таймаут:

gopackage main

import (
  "context"
  "fmt"
  "time"
)

func main() {
  ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
  defer cancel()

  select {
  case <-time.After(1 * time.Second):
    fmt.Println("operation completed")
  case <-ctx.Done():
    fmt.Println(ctx.Err())
  }
}

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

go"operation completed"

Здесь операция выполняется за 1 секунду, что меньше таймаута в 2 секунды, поэтому программа успешно завершается.

Пример с ручной отменой

Функцию отмены можно вызвать явно до истечения таймаута:

gopackage main

import (
  "context"
  "fmt"
  "time"
)

func main() {
  ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  defer cancel()

  go func() {
    time.Sleep(500 * time.Millisecond)
    cancel()
  }()

  select {
  case <-time.After(2 * time.Second):
    fmt.Println("operation completed")
  case <-ctx.Done():
    fmt.Println(ctx.Err())
  }
}

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

go"context canceled"

В этом примере функция отмены вызывается через 500 мс, поэтому контекст отменяется раньше таймаута.

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

  • функцию context.WithDeadline,
    которая отменяет контекст в конкретный момент времени
  • функцию context.WithCancel,
    которая создает контекст с ручной отменой
  • функцию context.Background,
    которая создает пустой корневой контекст
  • функцию context.WithTimeoutCause,
    которая позволяет указать причину отмены