Laravel выполняет асинхронные HTTP-запросы последовательно, а не одновременно

Не работает: я пытаюсь одновременно выполнить несколько 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(...) выполняются не одновременно, а последовательно?

Возможно, localhost:8000 чем-то управляет php -S?

Sammitch 14.09.2023 21:53

@Sammitch нет, на сервере есть несколько рабочих и он может обрабатывать запросы одновременно. В противном случае приведенные выше версии GuzzleHttp и Laravel Pool API также не будут работать, но на самом деле они выполняют запросы одновременно, а Http::async()->get(...) выполняет их последовательно.

PaulWen 15.09.2023 06:12

@Sammitch Я также обновил пример и больше не являюсь пользователем localhost, а вместо этого использую службу Postman's Echo Service. Это также упрощает воспроизведение проблемы, поскольку по времени выполнения вы можете сказать, что версии API GuzzleHttp и Laravel Pool API выполняются одновременно и требуют всего 3-4 секунды, в то время как версия Http::async()->get(...) работает 7-8 секунд, поскольку запросы выполняются последовательно. .

PaulWen 15.09.2023 06:31
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
3
108
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Документы показывают использование пула для достижения этой цели.

Фасад 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(). Может быть, именно это и является причиной беды?

PaulWen 26.09.2023 07:43
Ответ принят как подходящий

Благодаря @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

PaulWen 26.09.2023 08:33

Другие вопросы по теме