Sobes.tech
Senior
36

Біздің микросервис сыртқы API-ге, мысалы, төлем шлюзіне, шақыру керек болса, бірақ ол кенеттен баяулап немесе мүлде құлап қалса, сіз әдетте қосымшаны осындай көршілерден қалай қорғайсыз?

Сұралған компаниялар
наполеон

AI-дан жауап

sobes.tech AI

Чтобы защитить микросервис от зависимостей, которые могут тормозить или падать (например, внешнее API платежной системы), обычно применяют следующие подходы:

  1. Таймауты и ретраи — задавать разумные таймауты на запросы и ограниченное число повторных попыток.

  2. Circuit Breaker (автоматический выключатель) — если внешний сервис часто падает или отвечает медленно, circuit breaker временно блокирует вызовы к нему, чтобы не нагружать систему и не ждать долго.

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

  4. Fallback (запасной вариант) — при недоступности внешнего сервиса возвращать заранее подготовленные данные или заглушки.

  5. Мониторинг и алерты — отслеживать состояние вызовов и быстро реагировать.

В Go для реализации circuit breaker и таймаутов часто используют библиотеки вроде github.com/sony/gobreaker или github.com/afex/hystrix-go.

Пример с таймаутом и circuit breaker:

import (
    "context"
    "net/http"
    "time"

    "github.com/sony/gobreaker"
)

var cb *gobreaker.CircuitBreaker

func init() {
    cb = gobreaker.NewCircuitBreaker(gobreaker.Settings{
        Name:        "PaymentAPI",
        MaxRequests: 5,
        Interval:    60 * time.Second,
        Timeout:     30 * time.Second,
        ReadyToTrip: func(counts gobreaker.Counts) bool {
            return counts.ConsecutiveFailures > 3
        },
    })
}

func callPaymentAPI(ctx context.Context, url string) (*http.Response, error) {
    result, err := cb.Execute(func() (interface{}, error) {
        req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
        client := &http.Client{
            Timeout: 5 * time.Second, // таймаут на запрос
        }
        return client.Do(req)
    })

    if err != nil {
        // fallback или обработка ошибки
        return nil, err
    }

    return result.(*http.Response), nil
}

Таким образом, при проблемах с внешним сервисом наш микросервис не зависнет и сможет корректно обработать ситуацию.