Не работает: я пытаюсь одновременно выполнить несколько HTTP-запросов, используя HTTP-фасад Laravel.
К сожалению, когда я использую Http::async()->get(...), Laravel всегда выполняет их последовательно:
use Illuminate\Support\Facades\Http;
use GuzzleHttp\Promise\Utils;
$promises = [
Http::async()->get('https://postman-echo.com/delay/3'),
Http::async()->get('https://postman-echo.com/delay/3'),
];
$combinedPromise = Utils::all($promises);
$results = $combinedPromise->wait();
Работает: если вместо этого я использую API пула Laravel, запросы выполняются одновременно, как и ожидалось:
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\Pool;
$responses = Http::pool(fn(Pool $pool) => [
$pool->get('https://postman-echo.com/delay/3'),
$pool->get('https://postman-echo.com/delay/3'),
]);
Работает: Кроме того, используя GuzzleHttp напрямую, я могу выполнять запросы одновременно:
use GuzzleHttp\Client;
use GuzzleHttp\Promise\Utils;
$client = new Client([
'base_uri' => 'https://postman-echo.com'
]);
$promises = [
$client->getAsync('/delay/3'),
$client->getAsync('/delay/3'),
];
$combinedPromise = Utils::all($promises);
$results = $combinedPromise->wait();
Используемые версии: я тестировал с "laravel/framework": "9.47.0" и "laravel/framework": "10.14.1" в сочетании с PHP 8.2.1.
Вопрос: Кто-нибудь знает, почему мои вызовы Http::async()->get(...) выполняются не одновременно, а последовательно?
@Sammitch нет, на сервере есть несколько рабочих и он может обрабатывать запросы одновременно. В противном случае приведенные выше версии GuzzleHttp и Laravel Pool API также не будут работать, но на самом деле они выполняют запросы одновременно, а Http::async()->get(...) выполняет их последовательно.
@Sammitch Я также обновил пример и больше не являюсь пользователем localhost, а вместо этого использую службу Postman's Echo Service. Это также упрощает воспроизведение проблемы, поскольку по времени выполнения вы можете сказать, что версии API GuzzleHttp и Laravel Pool API выполняются одновременно и требуют всего 3-4 секунды, в то время как версия Http::async()->get(...) работает 7-8 секунд, поскольку запросы выполняются последовательно. .






Документы показывают использование пула для достижения этой цели.
Фасад Http возвращает объект Illuminate\Http\Client\PendingRequest.
Если PendingRequest async() имеет значение true, он не использует клиент повторно. Я предполагаю, что каждый вызов Http-фасада предоставляет отдельный клиентский объект.
Используйте тот же клиент, и все должно работать.
$client = Http::async();
$promises = [
$client->get('https://postman-echo.com/delay/3'),
$client->get('https://postman-echo.com/delay/3'),
];
Спасибо за ваш ответ и за ссылку на код PendingRequest Laravel 8! К сожалению, при тестировании с помощью Laravel 10 ваше предложение не работает, и запросы по-прежнему выполняются последовательно, а не одновременно. Также я заметил, что в Laravel 9 код немного изменился и больше не вызывает requestsReusableClient(). Может быть, именно это и является причиной беды?
Благодаря @txyoji, который указал мне правильный код Laravel, я смог найти решение, которое работает с Laravel 9 и 10:
use Illuminate\Support\Facades\Http;
use GuzzleHttp\Promise\Utils;
$client = Http::async();
$client = $client->setClient(new Client([
'handler' => $client->buildHandlerStack(),
'cookies' => true,
]));
$promises = [
$client->get('https://postman-echo.com/delay/3'),
$client->get('https://postman-echo.com/delay/3'),
];
$combinedPromise = Utils::all($promises);
$results = $combinedPromise->wait();
Поскольку Laravel 9 PendingRequest.buildClient() больше не вызывает PendingRequest.getReusableClient() для повторного использования одного и того же клиента GuzzleHttp в асинхронных запросах.
Приведенный выше код явно устанавливает клиент GuzzleHttp, который затем повторно используется в асинхронных запросах.
Я поднял пиар для Laravel Framework, чтобы это исправить: github.com/laravel/framework/pull/48546
Возможно,
localhost:8000чем-то управляетphp -S?