I'm trying to build a small application which will do a few things.
A main class will spawn, destroy, listen to, and manage workers...
<?php
namespace Queue;
class Controller extends Process
{
public $workers = array();
function __construct()
{
//Run the Process constructor before doing anything else.
parent::__construct();
}
function spawnWorker($businessId)
{
$this->workers[$businessId] = new \React\ChildProcess\Process("php index.php worker $businessId");
$this->workers[$businessId]->start($this->loop);
$this->workers[$businessId]->stdout->on("data", function($output) use(&$businessId) {
$this->channels->out->write("Child $businessId Said: " . $output);
});
}
function outputToWorker($businessId, $string)
{
$this->workers[$businessId]->stdin->write($string);
}
function run()
{
$this->loop->run();
}
}
A bunch of workers managed by the controller (eventually they will have a long running process which manages a queue defined in the database)...
<?php
namespace Queue;
class Worker extends Process
{
function __construct($businessId)
{
//Run the Process constructor before doing anything else.
parent::__construct();
// Assign a business to this worker.
$this->businessId = $businessId;
// Create a queue object for this worker.
$this->queue = new \stdClass;
}
function run()
{
$this->channels->in->on("data", function($input) {
$this->sendOutput($input);
});
$this->loop->run();
}
}
However, I ran across a situation where code did not do what I expected...
// Based on command line argument, decide which kind of process to spawn.
if (!isset($argv[1]) || $argv[1] === "controller")
{
$controller = new Controller;
$controller->spawnWorker(1);
$controller->outputToWorker(1, "Before Run");
$controller->run();
$controller->outputToWorker(1, "After Run");
} else if (strtolower($argv[1]) === "worker" && isset($argv[2]))
{
$worker = new Worker($argv[1]);
$worker->run();
}
This last bit of code is the file which I actually run to start the application. It routes which kind of process should be spawned based on command line arguments. (This way I don't have to have a file for a bunch of different kinds of processes.)
The worker is spawned correctly, and the first message (Child 1 Said: Before Run
) is sent to the worker, the worker sends it to stdout
and the controller
hears that event and sends it to it's own stdout
.
However, it seems the listener is a one-time listener, and the event loop is not reprocessing it over an over. Meaning, anytime after the initial run()
on controller
it will not respond to stdout
events from the worker.
Do I have to create my own explicit listeners with timers?