Symfony and ReactPHP Series — Chapter 5

Apisearch
Apisearch
May 18 · 3 min read

In the fourth chapter, we started turning our domain asynchronous, based on ReactPHP Promises, but because the Symfony Kernel is blocking, we had to turn our domain synchronous before returning to the server.

Symfony Async HTTP Kernel

So, if the problem is that the Symfony Kernel is synchronous, why don’t we make a small adapter to turn it asynchronous? I mean. Why don’t we modify the component to allow controllers to return Promises instead of Responses?

Well. This component already exists. You will see that the component is not stable and is under development, testing and performance checking, but for this posts series will be enough.

Add the dependency in your composer.json, update and you will be ready.

Only two extra steps to make your application full-promise-friendly instead of only-server-and-domain-promise-friendly.

  • Turn your kernel asynchronous. Easy. Open your kernel instance in src/Kernel.php and change the base used kernel
use Symfony\Component\HttpKernel\AsyncKernel as BaseKernel;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
  • Turn your simple ReactPHP server asynchronous. Add the flag --non-blocking when starting it. That will turn the server non-blocking, as you could guess, working properly with promises and the Async Kernel.

And run the benchmark. This report is for just one server, with one CPU, and the same specifications than before. As you can see, with a concurrency of 50 requests, the first 50% calls had an average of 70ms .

Percentage of the requests served within a certain time (ms)
50% 70
66% 74
75% 77
80% 79
90% 90
95% 213
98% 387
99% 407
100% 1267 (longest request)

But again. 1 thread. 1 CPU. Let’s use the 4 CPUs of our server, by installing 4 servers with an Nginx in front of them as a balancer.

Percentage of the requests served within a certain time (ms)
50% 53
66% 61
75% 68
80% 71
90% 82
95% 88
98% 96
99% 104
100% 1051 (longest request)

This number is insane. 56ms with a server that makes an external HTTP query that lasts around 20ms . Because the only work of that Nginx is to be a load balancer, working for example with Amazon ECS or Kubernetes, you could add simple load balancers and that would make the job (these servers are stateless, so the balancer can easily make round robin)

Who can work with Promises?

Working with Promises can really improve your code much more than you think. Of course, not everyone will be able to work with promises. For example, working with Doctrine and Promises at the same time, at the moment, is not possible. Any external communication should have an async way, like these libraries

All these projects return ReactPHP Promises instead of values (Another Promises would make the work as well, no need to be ReactPHP).

Of course, your services must be 100% stateless and something like a command bus would help you so much your architecture to be clean and performant.

More resources

Both projects

are being developed, improved and properly tested. You can use them, help us to improve and work with the community in order to allow projects like Doctrine to turn asynchronous sometime.

You can join as well the ReactPHP + Symfony channel in the Symfony-dev slack workspace. In that channel we discuss about the future of that adapter and the server.

Please, comment, test and give us your feedback about what would you improve.

Apisearch

Written by

Apisearch

An Open Source search engine. Give to your users instant and relevant results of all your data! 🔍💨😁