Search code examples
phploopsasynchronousreactphp

ReactPHP blocking inside a loop


I am trying to achieve a parallel execution of my workers and I'm using ReactPHP to help me. https://github.com/reactphp/react

But I'm not getting behaviour that I'm expecting to get.

Scenario:

I have three workers.

fetch.php parse.php notify.php

fetch.php and notify.php don't have prerequired conditions to run, so they can run in parallel and should run first.

parse.php needs to wait for fetch.php to finish with work and then it should execute.

So i have my parent script process.php where all the magic happens.

$tasks = ['fetch', 'notify'];

forkProcess($tasks);

function forkProcess($tasks)
{
   if (empty($tasks)) return false;

   $loop = React\EventLoop\Factory::create();

   foreach ($tasks as $task) {

       $process = new React\ChildProcess\Process("php $task.php");

       $loop->addTimer(0.001, function($timer) use ($process, $task) {
           $process->start($timer->getLoop());
           $process->stdout->on('data', function($output) use ($task) {
                echo $output;
                $subTasks = getDependentTask($task);
                forkProcess($subTasks);
           });
       });
   }

   $loop->run();

}

function getDependentTask($task)
{
    if ($task != 'fetch') return [];     
    return [
        'parse'      
    ];
}

So instead of getting this output:

FETCH
NOTIFY
PARSE

I am getting

FETCH
PARSE
NOTIFY

And script waits for parsing to finish and then goes to the next task which is notify.

So I am doing something wrong and since I'm playing around with ReactPHP for the first time its probably some rookie mistake.

Is the problem that I'm using recursion and that is blocking the loop or something else.

Maybe loop was not implemented to solve this kind of problems that I'm trying to solve?


Solution

  • I got it.

    Problem is with recursion.

    See in my first task fetch i have just a echo 'FETCH';

    And it's instant so it gets data immediately and it enters .on('data') event and calls function again with new array. So that is a design problem that I'm having.

    Figured it out immediately after i posted this question.

    If i edit my fetch.php worker and set sleep(1) before echo i get notify worker to output string first.