Как строить интеграцию со сторонним API: адаптер, anti-corruption layer, таймауты, ретраи
↑ 5.5 Интеграции со сторонними API: 1С, Битрикс24, FHIR · → Следующая
Зачем это на собесе
Про надёжность: что вы делаете, когда внешний сервис медленный, падает или меняет формат.
Объяснение
Внешняя система не под вашим контролем: у неё свои модели, лимиты и простои. Поэтому интеграцию изолируют.
| Приём | Зачем |
|---|---|
| Адаптер (порт + реализация) | доменный код зависит от своего интерфейса IPaymentGateway, а не от SDK |
| Anti-corruption layer (ACL) | перевод чужой модели в свою; чужие термины не протекают в домен |
| Таймауты | ограничить ожидание (на попытку и общий) |
| Retry с backoff + jitter | пережить кратковременные сбои; только идемпотентные вызовы |
| Circuit breaker | не долбить упавший сервис, быстро отказывать |
| Bulkhead / лимит параллелизма | сбой интеграции не забирает все потоки/соединения |
| Кэш и деградация | отдать последнее известное значение |
| Идемпотентность | ключи/дедупликация при повторах |
| Наблюдаемость | метрики, трейсы, логи запросов к внешним API (без секретов) |
public interface IPaymentGateway { Task<PaymentResult> ChargeAsync(Charge c, CancellationToken ct); }
public class AcmePaymentGateway(HttpClient http) : IPaymentGateway
{
public async Task<PaymentResult> ChargeAsync(Charge c, CancellationToken ct)
{
var resp = await http.PostAsJsonAsync("v2/charges", new AcmeChargeRequest(c.Amount.ToMinor(), c.Currency), ct);
var dto = await resp.Content.ReadFromJsonAsync<AcmeChargeResponse>(ct);
return AcmeMapper.ToDomain(dto!); // ACL: чужие статусы → наши
}
}
services.AddHttpClient<IPaymentGateway, AcmePaymentGateway>(c => c.BaseAddress = new("https://api.acme.example/"))
.AddStandardResilienceHandler();Нюансы и подводные камни
- Ретраить платёж без ключа идемпотентности — риск двойного списания.
- Без таймаута один медленный вызов занимает поток/соединение.
- Контракт внешнего API меняется: контрактные тесты и толерантный парсинг.
- Храните «сырой» ответ для отладки (осторожно с персональными данными).
- Ограничения провайдера (rate limit) учитывайте на своей стороне.
Практика
- Оберните сторонний SDK адаптером и напишите тесты с fake.
- Настройте таймауты, retry и circuit breaker и сымитируйте отказ через WireMock.
- Добавьте метрики успешных/неуспешных вызовов.
Вопросы с ответами
Что такое anti-corruption layer?
Слой перевода между чужой и своей моделью, не позволяющий внешним понятиям проникать в домен.
Когда можно ретраить?
Для идемпотентных операций и временных ошибок (5xx, таймаут, 429); для неидемпотентных — с ключом идемпотентности.
Зачем circuit breaker?
Быстрый отказ при заведомо неработающем сервисе экономит ресурсы и даёт ему восстановиться.