← Назад к вопросам

Что будешь делать если после запроса REST соединение сломается?

1.2 Junior🔥 121 комментариев
#ASP.NET и Web API

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Общий подход к обработке сбоя соединения в REST API

При сбое сетевого соединения после отправки REST запроса ключевая задача — определить, был ли запрос обработан сервером или нет. Это идемпотентность и идемпотентные операции становятся центральными концепциями. Я разделю стратегии на клиентскую и серверную стороны.

1. Клиентская сторона (Наша ответственность)

Основная тактика — повторные попытки (retry logic) с учетом идемпотентности операции.

Идемпотентные операции (GET, PUT, DELETE, PATCH*)

Для безопасных повторений используем экспоненциальную отсрочку (exponential backoff) и джиттер (jitter):

public class RetryHandler : DelegatingHandler
{
    private readonly int _maxRetries = 3;
    private readonly Random _jitter = new();
    
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, 
        CancellationToken cancellationToken)
    {
        HttpResponseMessage? response = null;
        
        for (int attempt = 1; attempt <= _maxRetries; attempt++)
        {
            try
            {
                response = await base.SendAsync(request, cancellationToken);
                if (response.IsSuccessStatusCode)
                    return response;
                    
                // Повторяем только при сетевых ошибках или 5xx
                if ((int)response.StatusCode < 500)
                    break;
            }
            catch (HttpRequestException ex)
            {
                // Логируем исключение
                _logger.LogWarning(ex, "Attempt {Attempt} failed", attempt);
            }
            
            if (attempt < _maxRetries)
            {
                var delay = TimeSpan.FromSeconds(Math.Pow(2, attempt)) 
                          + TimeSpan.FromMilliseconds(_jitter.Next(0, 1000));
                await Task.Delay(delay, cancellationToken);
            }
        }
        
        return response ?? throw new HttpRequestException("All retry attempts failed");
    }
}

Неидемпотентные операции (POST)

Для POST запросов, создающих ресурсы, стратегия сложнее:

  • Проверка по уникальному идентификатору — включаем Idempotency-Key в заголовки
  • Сначала локальная валидация, затем отправка
  • Компенсирующие транзакции (compensating transactions) для отката

2. Серверная сторона (Что должно быть реализовано)

Идемпотентность на сервере

[ApiController]
public class OrdersController : ControllerBase
{
    [HttpPost("orders")]
    public async Task<IActionResult> CreateOrder(
        [FromHeader(Name = "Idempotency-Key")] string idempotencyKey,
        [FromBody] OrderRequest request)
    {
        // Проверяем, не обрабатывался ли этот ключ ранее
        var existingOrder = await _idempotencyService
            .GetByKeyAsync(idempotencyKey);
        
        if (existingOrder != null)
            return Ok(existingOrder); // Возвращаем существующий результат
        
        // Обработка запроса и сохранение ключа идемпотентности
        var order = await _orderService.CreateAsync(request);
        await _idempotencyService.StoreAsync(idempotencyKey, order);
        
        return CreatedAtAction(nameof(GetOrder), new { id = order.Id }, order);
    }
}

3. Паттерны проектирования для надежности

Circuit Breaker (Автоматический выключатель)

// Используем Polly для реализации Circuit Breaker
var circuitBreakerPolicy = Policy<HttpResponseMessage>
    .Handle<HttpRequestException>()
    .OrResult(r => (int)r.StatusCode >= 500)
    .CircuitBreakerAsync(
        exceptionsAllowedBeforeBreaking: 3,
        durationOfBreak: TimeSpan.FromSeconds(30)
    );

Outbox Pattern для гарантированной доставки

Для критических операций, где потеря запроса недопустима:

  1. Сохраняем запрос в локальную БД (таблицу Outbox)
  2. Фоновая задача пытается отправить запросы из Outbox
  3. Помечаем запрос как отправленный после подтверждения

Компенсационные транзакции (Saga Pattern)

Для распределенных транзакций:

public class OrderSaga
{
    public async Task ProcessOrder(Order order)
    {
        try
        {
            await _inventoryService.ReserveItems(order.Items);
            await _paymentService.Charge(order.Total);
            await _shippingService.ScheduleDelivery(order);
        }
        catch (Exception)
        {
            // Компенсация всех выполненных шагов
            await Compensate(order);
            throw;
        }
    }
}

4. Мониторинг и анализ

  • Логирование всех попыток и сбоев с корреляционными идентификаторами
  • Метрики: количество сбоев, время восстановления, успешность retry
  • Alerting при превышении порога ошибок
  • Трассировка распределенных транзакций через OpenTelemetry

5. Практические рекомендации

Настройки HttpClient для production:

services.AddHttpClient("ResilientClient")
    .ConfigurePrimaryHttpMessageHandler(() => new SocketsHttpHandler
    {
        PooledConnectionLifetime = TimeSpan.FromMinutes(5),
        ConnectTimeout = TimeSpan.FromSeconds(30),
        ResponseDrainTimeout = TimeSpan.FromSeconds(15)
    })
    .AddPolicyHandler(GetRetryPolicy())
    .AddPolicyHandler(GetCircuitBreakerPolicy());

Ключевые параметры:

  • Таймауты: Connect, Send, Receive
  • Максимальное количество соединений
  • Lifetime пула соединений

Для пользовательского интерфейса:

  • Показывать индикатор выполнения
  • Предлагать повторить действие вручную
  • Сохранять состояние формы при transient failures

Заключение

Сбои соединений — не исключение, а норма в распределенных системах. Resilience engineering предполагает проектирование системы с учетом отказов. Современный подход — использовать комбинацию:

  1. Повторных попыток с интеллектуальными задержками
  2. Идемпотентности на уровне бизнес-логики
  3. Шаблонов устойчивости (Circuit Breaker, Retry, Timeout)
  4. Распределенных транзакций с компенсацией
  5. Исчерпывающего мониторинга

В .NET экосистеме библиотеки Polly, Coravel, MassTransit предоставляют готовые реализации этих паттернов. Важнее всего — определить SLA системы и выбрать стратегию, соответствующую бизнес-требованиям.