skip to Main Content

I was wondering if there is a way to have a ReactPHP HTTP Server handle requests Asynchronously. I set up a very basic HTTP Server using the documentation (https://github.com/reactphp/http)

HTTPServer.php

<?php

$httpServer = new ReactHttpServer(
    function(PsrHttpMessageServerRequestInterface $request) {
        $responseData = $request->getUri()->getPath();
        if($responseData == "/testSlow") {sleep(5);} // simulate a slow response time
        if($responseData == "/testFast") {sleep(1);} // simulate a fast response time
        return new ReactHttpMessageResponse(
            "200",
            array("Access-Control-Allow-Headers" => "*", "Access-Control-Allow-Origin" => "*", "Content-Type" => "application/json"),
            json_encode($responseData)
        );
    }
);

$socketServer = new ReactSocketServer("0.0.0.0:31");
$httpServer->listen($socketServer);

?>

It seems to working fine but Synchronously, if I send a request to the /testSlow path and then immediately to the /testFast path, the slow one will always finish first after 5 seconds and only once it has finished will the fast one then start and finish after 1 second

Am I missing some additional setup?

2

Answers


  1. ReactPHP’s event loop handles requests asynchronously, not in parallel. It means that there is only one running process. And call to sleep() hangs this process, i.e. prevents event loop from handling next requests. So, in asynchronous apps (in Node.js as well) it is a common practice to move heavy processing to dedicated processes.

    I am not ReactPHP expert, so cannot provide a working example, but can point the root cause of the problem. I would recommend to read this awesome blog: https://sergeyzhuk.me/reactphp-series, and this article in particular: https://sergeyzhuk.me/2018/05/04/reactphp-child-processes

    Login or Signup to reply.
  2. ReactPHP uses an EventLoop and works on single threaded PHP. This means that by calling sleep() in your code you block the main thread, therefore the EventLoop is blocked and ReactPHP and the PHP process won’t do anything for the time sleeping. Instead of using sleep() you need to set a timer on the event loop.

    Here is your example script rewritten:

    <?php
    $httpServer = new ReactHttpServer(
        function(PsrHttpMessageServerRequestInterface $request) {
            $responseData = $request->getUri()->getPath();
    
            $timeout = 0;
            if($responseData == "/testSlow") { // simulate a slow response time
                $timeout = 5;
            }
            if($responseData == "/testFast") { // simulate a fast response time
                $timeout = 1;
            }
    
            // create a promise that will resolve after $timeout seconds
            $promise = new ReactPromisePromise(function ($resolve, $reject) use ($timeout) {
                ReactEventLoopLoop::addTimer($timeout, function () use ($resolve) {
                    $resolve();
                });
            });
    
            // when the promise is resolved, this callback will create the HTTP response
            return $promise->then(function () use ($responseData) {
                return new ReactHttpMessageResponse(
                    "200",
                    array("Access-Control-Allow-Headers" => "*", "Access-Control-Allow-Origin" => "*", "Content-Type" => "application/json"),
                    json_encode($responseData)
                );
            });
        }
    );
    
    $socketServer = new ReactSocketServer("0.0.0.0:8080");
    $httpServer->listen($socketServer);
    
    ?>
    

    You can find more docs and examples on this topic in the official documentation of the react/http library and this specific bit at: https://github.com/reactphp/http#deferred-response.

    Hope this helps!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search