Правильная работа с таймаутами критична для надежности приложений.
Таймауты по умолчанию
http.Client без таймаута может зависнуть навсегда. Всегда устанавливайте Timeout.
client := &http.Client{
Timeout: 10 * time.Second,
}
Контекст в запросах
Передавайте контекст через NewRequestWithContext. Это позволяет отменять запросы.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, err := client.Do(req)
Раздельные таймауты
Транспорт позволяет настроить отдельные таймауты для соединения и чтения.
transport := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 5 * time.Second,
}).DialContext,
ResponseHeaderTimeout: 10 * time.Second,
}
Отмена запросов
При отмене контекста запрос немедленно прерывается. Это экономит ресурсы.
select {
case <-ctx.Done():
return ctx.Err()
case result := <-resultCh:
return result
}
Повторы с backoff
Комбинируйте таймауты с повторными попытками. Используйте экспоненциальную задержку.
Практические советы
Не используйте context.Background в обработчиках HTTP. Передавайте контекст запроса дальше.
Для внешних API устанавливайте короткие таймауты. Для внутренних сервисов можно увеличить.
Правильные таймауты предотвращают каскадные отказы и утечки ресурсов.
