Going Async in Symfony Controllers

Asynchronous programming has become a synonym for high performance in server side web applications in the recent years. This is largely due to the rising popularity of JavaScript and Node.js, in which everything is async by default.

Like many things, asynchronous programming is nothing new. You can use the programming model in a lot of environments from Python to .NET to browser runtimes with JavaScript. In fact, web developers working with browser JavaScript have used the paradigm since the 1990's.

Within the browser environment, individual events like clicking and are entered in an event loop (see Philip Roberts: What the heck is the event loop anyway?) which are then processed asynchronously: There is no guarantee on the order of when the click events will end execution.

The beef of going async is I/O. In the browser the concept was enabled in Internet Explorer 5.0 and popularised by Gmail in 2004. The method, coined as AJAX allowed the browser to make requests to the server after the initial page load.

Non-blocking asynchronous I/O on the server enables the server to continue performing other tasks instead of waiting for a long running database call, for example. There are a number of mechanisms for handing the flow of asynchronous code, such as futures/promises, generators and observables.

So asynchronous programming does not push your computer into overdrive to enable higher performance. What it can do is help the computer to use it's resources more efficiently, by removing time spent waiting.

Asynchronous PHP

By tradition PHP folllows the synchronous programming model. The computer performs the operations in the order they are given. This makes it straightforward and predictable to read code and anticipate the outcome.

The downside is that PHP can potentially spend a large portion of the execution time doing nothing, waiting for a remote server to respond with results or something else. This time could be spent better by proceeding with other tasks and returning to processing the DB results once they're done.

In the recent years there has been increased activity in the realm of Async PHP with projects such as React, Amphp, Icicle and RxPHP. There is also a book on Asynchronous PHP in the works. In addition the alternative PHP runtime HHVM and the PHP derivative Hack language has adopted async techniques.

During 2015 and early 2016 there has been positive advancements in this space for PHP. A number of the abovementioned efforts have joined the PHP-FIG (PHP Framework Interoperatibility Group) to work together to create conforming implementations and a PHP Async Interop Group has been formed:

Productive discussion on event loops @ async-interop. Very soon we will have a very important standard for #php - https://t.co/ZkMTmaxvRZ — Andrew Carter (@AndrewCarterUK) February 19, 2016

As you can see PHP is capable of working within the async paradigm with a number of event loop implementations, starting from native PHP implementation.

Asynchronous controllers in Symfony

The Symfony Framework itself is synchronous as the code flow is static, starting and ending to the front controller in a logical way. You can do asynchronous programming by deferring tasks to message queues to be handled by another process.

Sending emails or doing database maintenance tasks are great candidates for deferring to another process. But for tasks that you need to do within a scope of a single request, the asynchronous methods above can yield (pun intended) great results.

A typical example would be a request sent to a Content Management System that needs to generate a number of elements from a database to form a page for display. With Symfony you can use the fragment sub-framework and run tasks in parallel using ESI or Hinclude.

In some cases you can still benefit from async calls to optimise performance. As an example consider this Symfony controller built using Icicle Coroutines:

The controller simply returns a number of messages to the template. In this case, however it is done with a delay of one to five seconds. If done synchronously all the delays would add up to a maximum of 25 seconds. With coroutines the maximum runtime will be around fine seconds.

Conclusion

To gain asynchronous I/O your source needs to be non-blocking. Many common utils such as the MySQL library remain blocking, rendering async techniques useless. There are workarounds like Amphp MySQL, but it will take some time before the ecosystem is mature enough for async support to be default.

Mixing synchronous and asynchronous flows within a Symfony application seems like a valid use case. Explicitly entering an asynchronous loop when needed also keeps the code quite readable for developers used to the synchronous programming model.

PHP seems to be continuing to evolving and there are a lot of positive signs for standard methods for asynchronous programming methods. Joining the ReactiveX also enables JavaScript and PHP developers to share common concepts with RxPHP and RxJS.

Learn more about Async PHP:

Written by Jani Tarvainen on Saturday February 20, 2016

Permalink - Tags: symfony, async, php