Работа с API: Как на PHP реализовать ретраи (retry) для curl запросов, если сторонний сервис отдает ошибку 504 Gateway Timeout?

Ошибка 504 Gateway Timeout означает, что сторонний сервис не успел ответить вовремя. Чтобы не терять запросы и повысить надёжность интеграции, реализуют механизм повторных попыток (retry). Ниже — подробное руководство по реализации на PHP.

## Базовая реализация retry для cURL

php
function curlRequestWithRetry(string $url, array $options = [], int $maxRetries = 3, int $delay = 1): array {
$attempt = 0;
$lastError = »;

while ($attempt true,
CURLOPT_TIMEOUT => 10,
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);

if ($httpCode === 504 || $httpCode === 0) {
$attempt++;
$lastError = $curlError ?: «HTTP $httpCode»;
sleep($delay);
continue;
}

return [‘status’ => $httpCode, ‘body’ => $response];
}

return [‘status’ => 504, ‘body’ => null, ‘error’ => «Max retries reached. Last error: $lastError»];
}

## Экспоненциальная задержка (Exponential Backoff)

Простая фиксированная задержка может перегрузить сервис. Лучшая практика — увеличивать паузу с каждой попыткой:

php
function curlWithExponentialBackoff(string $url, int $maxRetries = 5): array {
for ($attempt = 0; $attempt true,
CURLOPT_TIMEOUT => 15,
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if (!in_array($httpCode, [504, 502, 503, 429])) {
return [‘status’ => $httpCode, ‘body’ => $response];
}

// Экспоненциальная задержка: 1s, 2s, 4s, 8s…
$sleepSeconds = pow(2, $attempt);
// Добавляем jitter для предотвращения thundering herd
$jitter = rand(0, 500) / 1000;
usleep(($sleepSeconds + $jitter) * 1_000_000);
}

return [‘status’ => 504, ‘body’ => null, ‘error’ => ‘All retries exhausted’];
}

## Какие HTTP-статусы стоит ретраить

— **504** — Gateway Timeout (основной случай)
— **502** — Bad Gateway
— **503** — Service Unavailable
— **429** — Too Many Requests (с учётом заголовка Retry-After)
— **0** — cURL timeout (CURLE_OPERATION_TIMEDOUT)

## Рекомендации по настройке

1. **Устанавливайте CURLOPT_TIMEOUT и CURLOPT_CONNECTTIMEOUT** — без них cURL может ждать бесконечно.
2. **Логируйте каждую попытку** — это помогает диагностировать нестабильность сторонних API.
3. **Не ретраить POST-запросы без идемпотентности** — повторный POST может создать дублирующиеся данные. Используйте идемпотентный ключ (Idempotency-Key) в заголовках.
4. **Ограничивайте максимальное время ожидания** — 3–5 попыток с экспоненциальным backoff обычно достаточно.
5. **Используйте Circuit Breaker** — если сервис недоступен долго, временно прекращайте попытки, чтобы не блокировать очередь задач.

Такой подход делает интеграцию с внешними API значительно более отказоустойчивой.


Задайте вопрос нейросети

Не нашли ответ? Спросите ИИ — он подготовит развёрнутую статью.