PHP Rotation and Longer Tasks

I am using ratchet php. I start like this:

$loop = \React\EventLoop\Factory::create(); $webSock = new \React\Socket\Server($loop); $webSock->listen($this->port, $this->host); $webServer = new \Ratchet\Server\IoServer( new \Ratchet\Http\HttpServer( new \Ratchet\WebSocket\WsServer( new PusherServer() ) ), $webSock ); return $loop; 

Now, in my onMessage() my Pusherserver class (which implements MessageComponentInterface ), I want to perform a long locking task. This will be an HTTP request, which can take up to ten seconds.

How to make onMessage() available to handle other requests during the execution of a previous HTTP request? I cannot use pthreads since I do not have access to change the php version that I have already provided (which is thread safe).

+5
source share
1 answer

This is exactly the problem that you should avoid when doing something in your event loop: it cannot be blocked, because someone else who is trying to subscribe or call a message, or anything else related to events, t will happen until it ends.

This is more of an architecture issue, and once you figure out how to do it, simplify it and make sure that it works for all the tasks you need.

Ratchet provides a ZMQ binding - that's awesome because once you configure it, everything you get on port 5555 will fall into your event loop in onYourMethodName() or whatever you want to name!

With this in mind, you need to send the work that needs to be executed to the job queue, another process (answer this child-process , which I especially dislike, because it is polling in user land, unlike I / O with interrupts, such like PHP PCNTL Extension ) or similar.

If you want to β€œjust make it work,” hide the work that needs to be done, along with the connection identifier or another identifier, so that you know which answer you need to return to in the child process and when it sent it. This will not block!

If you want to do it better, and I highly recommend learning this and the architecture for this, so that you can take this knowledge with you in your career when you approach the same asynchronous problem again, the fire-and-forget approach. Fire is what needs to be done in the job queue in the event loop, and then forget about it.

Your job queue can do this, and when it is done, run the result of this back through ZMQ (port 5555, which listens, will remember), which can then send the data back to the client.

websockets torrents image

For an amazing talk about work queues, I highly recommend this one from PHPNW.

Final note: since you open this thing and listen on port 5555 for data, you can send this data from anywhere. It can be interprocess communication, since your application has a Java application that sends data to port 5555 or literally everything. It ties things together, but doesn't tie them together, which is important in your architecture.


For an example of using ZMQ, they provide all this on this page here (as indicated above), but I will try and explain a little bit what is happening.

 $pull->bind('tcp://127.0.0.1:5555'); $pull->on('message', array($pusher, 'onYourMethodName')); 

This part means that when something sends data to port 5555, and this is a "message" (you can use other options available instead of Google), it will call onYourMethodName in your $pusher object. It really is that simple. Something over 5555 hit $pusher::onYourMethodName .

As a result, you just need to create your method in the event handler (next to onMessage() , onSubscribe() , etc.) ... Again, all this is mentioned on this page.

 public function onYourMethodName($data) { /** You'll probably want to send the data in JSON format **/ /** Imagine you get through a 'topic' in here... **/ $data = json_decode($data, true); /** You should already have stored the people who are connected, topics etc - see the tutorial **/ $topic = $this->subscribedTopics[$data['topic']]; /** Send the data out to everyone subscribed to this topic **/ $topic->broadcast($data); } 

If you want to be able to send data to a specific user, and not to everyone, there are many ways to do this. Take a look at this question , as I did, but it was some time ago.

The only thing you need to do now is in your handler (in onMessage or something else), actually put what needs to be done in the queue, and also with whom it should be sent back (topic).

At the end of your employee doing this and receiving the data, he needs to call this to click on the code that I showed above:

 $context = new ZMQContext(); $socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher'); $socket->connect("tcp://localhost:5555"); $socket->send(json_encode($data)); 

So here is what you need to do:

  • Get the first bit that works with listening on port 5555
  • Create your method in an event handler, etc.
  • Do not worry about queues or something else.
  • Create a really simple php script that executes the above 4 lines of code, and prove that when you run this script separately, it really sends data to the event loop
  • Then think about how to add it in turn and get your workers to process it.
+7
source

All Articles