Что такое Context в Golang

Context — это Golang пакет включающий структуру Context и вспомогательные функции.

Основная идея этого пакета — контролировать время выполнения сетевых запросов (http, tcp and etc.)

С помощью него можно установить таймаут для запроса

context.WithTimeout (функция является оберткой над context.WithDeadline)

или отменить по условию

context.WithCancel()

Отмена запроса по таймауту

  • Пример из жизни. Вы звоните другу и ждёте пока он ответит. Обычно вы ждёте какое-то время, за которое он должен ответить на звонок, например 20 секунд. Если он так и не взял трубку, вы отменяете вызов.
  • Пример реальной задачи. Скрипт ежедневно забирает данные по API из внешнего сервиса. Задача — завершить запрос к API, если он не выполнился в течении 20 секунд.

В следующем примере также используется функция context.Background() . Она возвращает пустой контекст (обычно он используется для инициализации контекстов).

Пример кода:

// создается контекст с таймаутом, первый аргумент функции родительский контекст.
ctx, cancel := context.WithTimeout(context.Background(), 20 * time.Second)
defer cancel()

// создается заспрос с использованием контекста.
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "<api_url>", nil)
if err != nil {
	return nil, fmt.Errorf("failed to create request with ctx: %w", err)
}

// отправка запроса.
res, err := http.DefaultClient.Do(req)
if err != nil {
	return nil, fmt.Errorf("failed to perform http request: %w", err)
}

return res, nil

Отмена запроса по условию

  • Пример из жизни. Вы школьник и не можете решить задачу по математике. Идёте к родителям и сестре за помощью. Мама, папа и сестра начали решать задачку, сестра решила первая. В итоге вы говорите родителям, что задачу больше решать не надо, сестра уже решила.
  • Пример реальной задачи. Скрипт ищет сервер, который ответит быстрее всех. Идёт отправка запросов на 10 серверов. Когда получили первый ответ, отменяем все остальные запросы.

Пример кода:

	var servers = []string{"<SERVER_URL_1>", "<SERVER_URL_2>", "<SERVER_URL_3>"}
	var wg sync.WaitGroup

	// создается контекст. Аргумент родительский контекст.
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// цикл по серверам, среди которых ищем самый быстрый.
	for _, url := range servers {
		wg.Add(1)
		go func() {
			// создается заспрос и использованием контекста.
			req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
			if err != nil {
				fmt.Errorf("failed to create request with ctx: %w", err)
			}

			// Отправка запроса.
			_, err = http.DefaultClient.Do(req)
			if err != nil {
				fmt.Errorf("failed to perform http request: %w", err)
			}
			wg.Done()

			// Ответ получен отменяем контекст. Все остальные запросы отменятся в этот момент.
			cancel()
		}()
	}
	wg.Wait()

.....

go func() {
			for {
				select {
				case <-ctx.Done():
                // Здесь код исполнится, когда самый быстрый сервер найден.
					return
				}
			}
		}()

Видео о контексте в Golang

Рекомендуем к прочтению



Оставить комментарий

Этот сайт защищен reCAPTCHA и применяются Политика конфиденциальности и Условия обслуживания применять.

Срок проверки reCAPTCHA истек. Перезагрузите страницу.