PHP
Web Services
Asynchronous Programming
Server-Side Development
API Integration

PHP Async Web Services

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

When people say "async web services" in PHP, they usually mean one of two things: making multiple I/O calls concurrently, or building a long-running non-blocking HTTP service. PHP can do both, but the design choices are different from the traditional one-request-per-process model many developers know from PHP-FPM.

What Async Actually Solves

Asynchronous programming helps when the bottleneck is waiting, not CPU work. If a request needs to call three remote APIs, read from Redis, and push a webhook, async can overlap those waits instead of blocking on each one in sequence.

That means async is most useful for:

  • HTTP API aggregation
  • websocket or long-poll servers
  • queue consumers
  • notification or webhook systems

It is less useful for pure CPU-heavy work, where PHP still needs separate workers or processes for real parallelism.

Concurrent HTTP Calls with Guzzle Promises

For many PHP applications, the simplest async step is concurrent outbound HTTP requests. Guzzle supports this with promises.

php
1<?php
2
3require 'vendor/autoload.php';
4
5use GuzzleHttp\Client;
6use GuzzleHttp\Promise\Utils;
7
8$client = new Client(['timeout' => 5.0]);
9
10$promises = [
11    'users' => $client->getAsync('https://jsonplaceholder.typicode.com/users'),
12    'posts' => $client->getAsync('https://jsonplaceholder.typicode.com/posts'),
13];
14
15$responses = Utils::unwrap($promises);
16
17foreach ($responses as $name => $response) {
18    echo $name . ': ' . $response->getStatusCode() . PHP_EOL;
19}

This pattern is useful when your PHP service is aggregating several external services before returning a response.

Event-Loop Frameworks for Non-Blocking Services

If you want a truly asynchronous server process, use an event-loop-based framework such as ReactPHP or Amp. Those tools let a single PHP process handle many I/O-bound operations without blocking on each one.

A simple ReactPHP HTTP service looks like this:

php
1<?php
2
3require 'vendor/autoload.php';
4
5use Psr\Http\Message\ServerRequestInterface;
6use React\Http\HttpServer;
7use React\Http\Message\Response;
8use React\Socket\SocketServer;
9
10$server = new HttpServer(function (ServerRequestInterface $request) {
11    return new Response(
12        200,
13        ['Content-Type' => 'application/json'],
14        json_encode(['ok' => true])
15    );
16});
17
18$socket = new SocketServer('127.0.0.1:8080');
19$server->listen($socket);
20
21echo "Server running on http://127.0.0.1:8080\n";

That is very different from PHP-FPM. It is a long-running process, so connection handling, memory behavior, and shutdown discipline matter much more.

PHP-FPM Is Still Request-Oriented

A common misunderstanding is thinking async inside PHP automatically changes how PHP-FPM works. It does not. Under PHP-FPM, each inbound request still occupies a worker. Async I/O can make that worker spend less time blocked on remote calls, but it does not transform PHP-FPM into an event-loop server.

That distinction matters when choosing architecture:

  • use concurrent clients inside PHP-FPM for API aggregation
  • use ReactPHP, Amp, or similar when you want a long-running async service model

Error Handling Changes in Async Code

Async code is not harder because the syntax is magical. It is harder because failures happen later and in different places. Timeouts, connection resets, and partial failures have to be handled explicitly.

That means production async services need:

  • timeouts
  • retries where appropriate
  • cancellation or backpressure strategies
  • structured error logging

Without those, async code quickly becomes harder to reason about than the synchronous version it replaced.

Common Pitfalls

  • Expecting async to speed up CPU-bound PHP code.
  • Using async libraries without understanding the event loop or promise lifecycle.
  • Forgetting that PHP-FPM still allocates one worker per inbound request.
  • Launching concurrent outbound calls without setting explicit timeouts.
  • Writing long-running async services as if they were short-lived request scripts.

Summary

  • Async PHP is mainly about overlapping I/O, not making CPU work parallel.
  • Guzzle promises are a practical entry point for concurrent outbound HTTP calls.
  • ReactPHP and Amp are better fits for long-running non-blocking services.
  • PHP-FPM remains request-oriented even when your code uses async clients.
  • Timeouts, retries, and failure handling are essential in async web-service code.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.