0

I have the following scenario:

I have an API built with the Slim PHP framework. I am using the PHP lib Ratchet to run a WebSocket server. Once the WebSocket server is started, I want to run a function that does some computation while the server is running.

So far, inside my API, I have a route that calls the MyMethod method of a class MyClass. Inside the class, I have the following:

class MyClass {
public $calculation_status;
public function MyMethod() {
    $server = IoServer::factory(
            new HttpServer(
                new WsServer(
                    new messengerApp($this)
                )
            ),
            8080
        );

        $this->doCalculationAsynchronously()->then(
            function ($result) {
                $this->calculation_status = 'finished';
            },
            function ($reason) {
                $this->calculation_status = 'stopped';
            },
            function ($update) {
                $this->calculation_status = 'still working...';
            }
        }

        $server->run($this);
    }
    public function doCalculationAsynchronously() {
        $deferred = new Deferred();
        $this->computeSomethingAsync(function ($error = null, $result) use ($deferred) {
            if ($error) {
                $deferred->reject($error);
            } else {
                $deferred->resolve($result);
            }
        });

        return $deferred->promise();
    }

    public function computeSomethingAsync() {

        // Simulate a long running calculation
        while(true){} // OR sleep(1000000);


        return $result;
    }
}

So, I'm expecting this to try to start running the asynchronous calculation function, return a promise to MyMethod, and then run my WebSocket server.

The reason for injecting $this into the server is to access my calculation_status property and be able to send it to clients through the WS.

This code is inspired by the example for Deferred in the ReactPHP doc

Note: If I don't have the forever while loop, it goes on and runs the server correctly (but this is synchronous behavior; my goal for the server is to send the calculation status to clients). Injecting the class into the object works fine as well.

Neo_999
  • 151
  • 1
  • 1
  • 9
  • Can you explain what **exactly** does not work as expected with the given code? – Nico Haase Mar 20 '19 at 18:31
  • `while(true){}` this will block the process – Sindhara Mar 20 '19 at 18:35
  • It does not get to $server->run before the calculation is done. I'm expecting it to start the calculation and move on and start the websocket server.before the calculation is finished. – Neo_999 Mar 20 '19 at 18:37
  • @kuh-chan This is basically what my question is about. Why is the while(true){} blocking everything? Isn't using Deferred with a Promise supposed to solve that? – Neo_999 Mar 20 '19 at 18:44
  • No; PHP ist still single threaded. Frameworks like React are just implementing Multitasking with a lot of magic. So if a task is stuck (e.g. by a blocking loop), the whole thread will be stuck. I think your function should look like `public function computeSomethingAsync($callable) {/* do stuff */ $callable($error, $result);}` – Sindhara Mar 20 '19 at 18:49
  • 1
    Your issue is your assumption of asynchronous = multithreaded. This is _not_ true. Asynchronous does not mean it's multithreaded. If you need parallelism, you need more proccesses or threads. One thread is still one thread, it can't do more than one thing at a time. So what you probably want is to run the computation in a different process. See the [child process component](https://github.com/reactphp/child-process) by ReactPHP. – Charlotte Dunois Mar 25 '19 at 17:37
  • @Charlotte_Dunois, after doing some more reading and tests on my own, I believe you are on the right track. I actually ended up launching the WebSocket server as a separate process. The ChildProcess method, though, is probably the better way to do it. I would accept your comment if you elaborate a bit more in an answer. – Neo_999 Mar 26 '19 at 18:27

0 Answers0