Three external calls on one page: prices, stock, delivery estimate. Each answers in about 300 ms. The page waits a full second, because we call them one after another. PHP is synchronous, what can you do.

Turns out, something. Symfony HttpClient is lazy. request() sends and returns immediately. The waiting happens when you read the response. So start all three, read later:

$prices   = $client->request('GET', $pricesUrl);
$stock    = $client->request('GET', $stockUrl);
$delivery = $client->request('GET', $deliveryUrl);

$data = [
    'prices'   => $prices->toArray(),
    'stock'    => $stock->toArray(),
    'delivery' => $delivery->toArray(),
];

Under the hood it is curl multi. Three requests fly at once, wall time is the slowest one instead of the sum. Our second became 350 ms. No swoole, no reactphp, no async rewrite. Same boring controller.

Two things to get right.

Timeouts. Sequential, one slow service made the page slow. Parallel, one hanging service still hangs the page, only now with company. Set a per-request timeout that fits the total budget, and decide what the page shows when the delivery estimate did not come. Usually an empty block, and nobody dies.

Fan-out. The first time this trick works, someone applies it to a loop over two hundred items and fires two hundred concurrent requests at a partner API. The partner notices. Batch the loop, or use stream() and keep a fixed number in flight.

Sequential external calls are the cheapest latency win I know right now. Open your slowest endpoint, count the calls that do not depend on each other. Overlap them.

The someone in the fan-out paragraph was me. On a Friday.