Sobes.tech
Senior

De service doet verzoeken naar een externe API die begint te antwoorden na 10 seconden. Goroutines stapelen zich op, het geheugen groeit, en de service crasht door OOM. Hoe te beschermen?

sobes.tech AI

Antwoord van AI

Проблема в том, что горутины блокируются на долгих запросах к внешнему API, что приводит к накоплению горутин и росту потребления памяти.

Как защитить сервис:

  1. Ограничить количество одновременно выполняющихся запросов — использовать семафор или пул воркеров, чтобы не создавать слишком много горутин.

  2. Установить таймауты на HTTP-запросы — использовать контекст с таймаутом (context.WithTimeout) или настроить таймауты в HTTP-клиенте, чтобы запросы не висели бесконечно.

  3. Обрабатывать ошибки и отменять запросы при таймауте — чтобы горутины не блокировались.

  4. Использовать контекст для отмены запросов — передавать context.Context в функции, чтобы можно было отменить запрос при необходимости.

Пример с таймаутом и ограничением количества одновременных запросов:

var semaphore = make(chan struct{}, 10) // максимум 10 одновременных запросов

func callExternalAPI(ctx context.Context, url string) error {
    semaphore <- struct{}{}         // захватить слот
    defer func() { <-semaphore }() // освободить слот

    ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
    if err != nil {
        return err
    }

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    // обработка ответа
    return nil
}

Такой подход предотвратит накопление горутин и падение по OOM.