Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як налаштувати повторні спроби HTTP-запитів у Laravel і що не варто повторювати?

Метод retry повторює запит при помилці:

Http::retry(3, 200)->get($url);                       // 3 спроби, 200 мс між ними
Http::retry([100, 500, 2000])->get($url);             // затримки по черзі
Http::retry(4, fn (int $attempt) => 2 ** $attempt * 100)->get($url);   // експоненційно

Сигнатура: retry(array|int $times, Closure|int $sleepMilliseconds = 0, ?callable $when = null, bool $throw = true).

Третій аргумент - коли повторювати. За замовчуванням повтор іде при будь-якій помилці - і клієнтській (4xx), і серверній. Це рідко правильно:

use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Http\Client\RequestException;

Http::retry(3, 300, function (Throwable $exception, PendingRequest $request) {
    if ($exception instanceof ConnectionException) {
        return true;                                   // мережа, тайм-аут
    }

    return $exception instanceof RequestException
        && in_array($exception->response->status(), [429, 500, 502, 503, 504], true);
})->get($url);

Що повторювати: мережеві збої, тайм-аути, 502/503/504, 429 (краще з урахуванням Retry-After).

Що НЕ повторювати:

  • 400, 404, 422 - повтор дасть ту саму відповідь;
  • 401/403 - хіба що після оновлення токена: колбек може змінити запит ($request->withToken($newToken)) і повернути true;
  • неідемпотентні операції (POST на створення платежу, відправка SMS) без ключа ідемпотентності: таймаут не означає, що запит не дійшов - повтор може списати гроші двічі.

throw: false - після всіх спроб повернути останню відповідь замість винятку. Але ConnectionException кидається все одно, якщо всі спроби впали через з'єднання.

Повтори в запиті користувача vs у черзі:

  • синхронно - лише короткі повтори (1-2 спроби, сотні мілісекунд): користувач чекає, а процес PHP зайнятий;
  • у джобі - довгі затримки краще віддати черзі ($tries, backoff()): джоба звільняє воркер між спробами, а не спить у usleep.

Не множити повтори. Http::retry(3) всередині джоби з $tries = 5 - до 15 запитів на одну операцію, а з повторами на рівні проксі чи SDK - ще більше. Кожен рівень, що повторює, - вирішується свідомо.

Випадковий розкид затримки (jitter) для масових інтеграцій - щоб сотні джоб після збою провайдера не вдарили по ньому одночасно.

Докладніше в документації: HTTP-клієнт: повторні спроби

Схожі питання