public function runTestProcess($arguments, $expectedExitCode = 0, $timeout = 5) { $command = __DIR__ . '/../../../../bin/phpunit-parallel ' . $arguments; $loop = Factory::create(); $p = new Process($command); $p->start($loop); $stdout = ''; $stderr = ''; $timer = $loop->addTimer($timeout, function () use($arguments, $p, $stdout, $stderr) { $p->terminate(SIGKILL); $this->fail("running phpunit-parallel with '{$arguments}' did not complete in time\nstdout: {$stdout}\nstderr: {$stderr}\n"); }); $p->stdout->on('data', function ($data) use(&$stdout) { $stdout .= $data; }); $p->stderr->on('data', function ($data) use(&$stderr) { $stderr .= $data; }); $p->on('exit', function () use($timer) { $timer->cancel(); }); $loop->run(); if ($p->getExitCode() !== $expectedExitCode) { $this->fail("Process exited with code {$p->getExitCode()}, expected {$expectedExitCode}\nstdout: {$stdout}\nstderr: {$stderr}\n"); } return [$stdout, $stderr]; }
protected function execute(InputInterface $input, OutputInterface $output) { $arguments = $this->getCommandArguments($input); $builder = $this->getEnvironmentHelper()->getProcessBuilder($arguments); $command = $builder->getProcess()->getCommandLine(); $loop = Factory::create(); $process = new Process($command, $this->getEnvironmentHelper()->getCwd()); $port = (int) $input->getOption('port'); $server = $this->initializeServer($loop, $port); $started = false; $this->addEnvironmentInfo($port, $command); $loop->addPeriodicTimer(self::LOOP_TIMER_PERIOD, function (Timer $timer) use($output, $process, $server, &$started) { $clients = $server->getConnections(); if (true === $started && false === $process->isRunning()) { exit($process->getExitCode()); } if ($clients->count()) { if (!$process->isRunning()) { $process->start($timer->getLoop()); $started = true; $this->broadcastToClients($clients); } $callable = function ($output) use($clients) { $this->buffer .= $output; $this->broadcastToClients($clients); }; $process->stdin->on('data', $callable); $process->stdout->on('data', $callable); $process->stderr->on('data', $callable); } }); $server->bind(); $loop->run(); }
public function __construct(LoopInterface $loop, SpawnerInterface $spawner, $id, $cmd, $args, $onData, $onExit) { $this->id = $id; $this->loop = $loop; $this->process = new Process($spawner->spawn($cmd, $args)); $this->process->on('exit', function ($exitCode, $termSignal) use($onExit) { call_user_func($onExit, $exitCode, $termSignal); }); $this->process->start($loop); $this->out = $this->process->stdout; $this->in = $this->process->stdin; $this->err = $this->process->stderr; $this->out->on('data', function ($data) use($onData) { call_user_func($onData, $data); }); $this->err->on('data', function ($data) use($onData) { call_user_func($onData, $data); }); }
/** * @param Process $process * @param LoopInterface $loop * @param array $options * @param float $interval * @return \React\Promise\PromiseInterface */ public static function parent(Process $process, LoopInterface $loop, array $options = [], $interval = self::INTERVAL) { $process->start($loop, $interval); return \WyriHaximus\React\tickingPromise($loop, $interval, [$process, 'isRunning'])->then(function () use($process, $options) { $messenger = new Messenger($process->stdin, $process->stdout, $process->stderr, ['read_err' => 'stderr', 'read' => 'stdout', 'write' => 'stdin', 'callForward' => function ($name, $arguments) use($process) { return call_user_func_array([$process, $name], $arguments); }] + $options); Util::forwardEvents($process, $messenger, ['exit']); return \React\Promise\resolve($messenger); }); }
public function testTerminatingProcessReturnsError() { $process = new Process('echo nevermind && cat'); $process->start($this->loop); $zen = new BaseZen(); $zen->go($process); $this->loop->addTimer(0.1, function () use($process) { $process->terminate(SIGKILL); }); $this->loop->run(); $zen->promise()->then(null, $this->expectCallableOnce()); }
/** * {@inheritdoc} * @param LoopInterface $loop * @param float $interval */ public function start(LoopInterface $loop, $interval = 0.1) { if ($this->isRunning()) { return; } $this->startedAt = microtime(true); $this->once('exit', function ($exitCode, $termSignal) use($loop) { $this->startedAt = null; //Auto restart if ($termSignal !== 15 && $this->autoRestart === true) { $this->start($loop); } }); parent::start($loop, $interval); }
/** * launch the given interactive $command shell * * Its STDOUT will be used to parse responses, the STDIN will be used * to pass commands. * * If the command prints output to STDERR, make sure to redirect it to * STDOUT by appending " 2>&1". * * @param string|Process $process accepts either a command string to execute or a Process instance * @return DeferredShell */ public function createDeferredShell($process) { if (!$process instanceof Process) { $process = new Process($process); } $process->start($this->loop); $stream = new CompositeStream($process->stdout, $process->stdin); // forcefully terminate process when stream closes $stream->on('close', function () use($process) { if ($process->isRunning()) { $process->terminate(SIGKILL); } }); return new DeferredShell($stream); }
/** * */ public function serverAction($argv) { $config = $this->di->getConfig(); $help = <<<HELPMSG * PHP Ratchet websocket server on port {$config->app->wsPort} * ZMQ server on port {$config->app->zmqPort} * Node.js/Gulp Webpack build environment server on port {$config->dev->webpackPort} HELPMSG; $params = $this->parseArgs($argv, ['title' => "Start the dev (development) server processes", 'help' => $help, 'args' => ['required' => [], 'optional' => []], 'opts' => []]); $devDir = $this->config->dev->path->devDir; $cmdWebirdEsc = escapeshellcmd("{$devDir}/webird.php"); $devDirEsc = escapeshellarg($devDir); $websocketProc = new Process("{$cmdWebirdEsc} websocket"); $webpackProc = new Process("cd {$devDirEsc} && npm run dev"); $loop = EventLoopFactory::create(); $loop->addTimer(0.001, function ($timer) use($websocketProc, $webpackProc) { $websocketProc->start($timer->getLoop()); $this->addProcOutputListener($websocketProc); $webpackProc->start($timer->getLoop()); $this->addProcOutputListener($webpackProc); }); $loop->run(); }
/** * */ public function serverAction($argv) { $config = $this->config; $help = <<<HELPMSG * PHP Ratchet websocket server on port {$config->app->wsPort} * ZMQ server on port {$config->app->zmqPort} HELPMSG; $params = $this->parseArgs($argv, ['title' => 'Start the dist (distribution/production) server processes.', 'help' => $help, 'args' => ['required' => [], 'optional' => []], 'opts' => ['w|wsport:' => "websockets listen on port (default is {$config->app->wsPort}).", 'z|zmqport:' => "zmq listen on port (default is {$config->app->zmqPort})."]]); $appDir = $this->config->path->appDir; $cmdWebirdEsc = escapeshellcmd("{$appDir}/webird.php"); $websocketProc = new Process("{$cmdWebirdEsc} websocket"); $loop = EventLoopFactory::create(); $loop->addTimer(0.001, function ($timer) use($websocketProc) { $websocketProc->start($timer->getLoop()); $websocketProc->stdout->on('data', function ($output) { echo $output; }); $websocketProc->stderr->on('data', function ($output) { echo $output; }); }); $loop->run(); }
/** * @return null */ protected function initReplyStackProcess() { $this->replyStackProcess = new Process($this->publisherPulsarDto->getReplyStackCommandName()); $this->replyStackProcess->on(EventsConstants::PROCESS_EXIT, function ($exitCode, $termSignal) { $this->logger->warning("Reply stack sub-process exit with code: " . serialize($exitCode) . " | and term signal: " . serialize($termSignal)); }); $this->replyStackProcess->start($this->loop); $this->logger->debug("Init reply stack process."); /** * $data is serialized ReplyStackErrorDto */ $this->replyStackProcess->stdout->on(EventsConstants::DATA, function ($data) { $this->logger->debug($data); //throw new PublisherPulsarException("Error in STDOUT due to initReplyStackProcess. " . $data); }); $this->replyStackProcess->stderr->on(EventsConstants::DATA, function ($data) { $this->logger->critical($data); throw new PublisherPulsarException("Error in STDERR due to initReplyStackProcess. " . $data); }); $replyStackDto = new ReplyStackDto(); $replyStackDto->setReplyStackVsPulsarSocketAddress($this->pulsarSocketsParams->getReplyToReplyStackSocketAddress()); $replyStackDto->setReplyStackVsPerformersSocketAddress($this->pulsarSocketsParams->getReplyStackSocketAddress()); $replyStackDto->setLogger($this->publisherPulsarDto->getLogger()); $replyStackDto->setModuleName($this->publisherPulsarDto->getModuleName()); $this->replyStackProcess->stdin->write(serialize($replyStackDto)); $this->startAwaitBeReadyToAct = microtime(true); return null; }
/** * @param InputInterface $input * @param OutputInterface $output * * @return void */ protected function executeMultiThreadStreamManager(InputInterface $input, OutputInterface $output) { /** @var Generator $streams */ $streams = $this->getContainer()->get('sim.event_store.replay')->streams(); $loop = Factory::create(); $threads = 0; $iteration = 0; $loop->addPeriodicTimer(0.001, function ($timer) use($loop, $streams, &$threads, &$iteration, $input, $output) { if ($threads >= $input->getOption('threads')) { return; } if (!$streams->valid()) { $loop->stop(); } $threads++; $stream = $streams->current(); $output->writeln(sprintf('<info>Dispatching thread for event stream %s</info>', $stream)); $process = new Process(sprintf('app/console simgroep:eventsourcing:events:replay %s --stream %s', $input->getArgument('projector'), $stream)); $process->on('exit', function ($exitCode, $termSignal) use(&$threads, $output) { $threads--; if ($exitCode !== 0) { $output->writeln(sprintf('<error>Process ended with code %s</error>', $exitCode)); } }); $process->start($timer->getLoop()); if ($input->getOption('verbose')) { $process->stdout->on('data', function ($message) use($output) { $output->write($message); }); } $output->writeln(sprintf('<info>Stream %s | %s streams/sec</info>', str_pad(++$iteration, 10, ' ', STR_PAD_LEFT), str_pad($this->perSecond($iteration), 6, ' ', STR_PAD_LEFT))); $streams->next(); }); $loop->run(); }
private function run(array $args = array()) { $command = $this->bin; foreach ($args as $value) { $command .= ' ' . escapeshellarg($value); } // var_dump($command); $process = new Process($command); $process->start($this->loop); return $process; }
/** * Start process on the loop passed */ public function start(LoopInterface $loop, $interval = 0.1) { $this->send(self::EVENT_BEFORE_START); // Initialize variables $this->loop = $loop; $this->elapsed = 1; // The first time this is used, one second is elapsed already $this->hanged = false; // Start process parent::start($this->loop, $interval); if (!$this->hasTimer()) { // For every tick of the timer, check if process is hanging, // and update elapsed time $self = $this; $timer =& $this->timer; $elapsed =& $this->elapsed; $hanged =& $this->hanged; $this->timer = $loop->addPeriodicTimer(1, function (TimerInterface $t) use($self, &$timer, &$elapsed, &$hanged) { $self->send($self::EVENT_ELAPSED); // If process is hanging, interrupt it if ($self->isHanging()) { $hanged = true; $self->send($self::EVENT_HANGING); $self->terminate(); } // Increment elapsed time $elapsed++; }); } $this->send(self::EVENT_AFTER_START); }
public function testTerminateWithStopAndContinueSignalsUsingEventLoop() { if (defined('PHP_WINDOWS_VERSION_BUILD')) { $this->markTestSkipped('Windows does not report signals via proc_get_status()'); } if (!defined('SIGSTOP') && !defined('SIGCONT')) { $this->markTestSkipped('SIGSTOP and/or SIGCONT is not defined'); } $loop = $this->createloop(); $process = new Process('sleep 1; exit 0'); $called = false; $exitCode = 'initial'; $termSignal = 'initial'; $process->on('exit', function () use(&$called, &$exitCode, &$termSignal) { $called = true; $exitCode = func_get_arg(0); $termSignal = func_get_arg(1); }); $loop->addTimer(0.001, function (Timer $timer) use($process) { $process->start($timer->getLoop()); $process->terminate(SIGSTOP); $this->assertSoon(function () use($process) { $this->assertTrue($process->isStopped()); $this->assertTrue($process->isRunning()); $this->assertEquals(SIGSTOP, $process->getStopSignal()); }); $process->terminate(SIGCONT); $this->assertSoon(function () use($process) { $this->assertFalse($process->isStopped()); $this->assertEquals(SIGSTOP, $process->getStopSignal()); }); }); $loop->run(); $this->assertTrue($called); $this->assertSame(0, $exitCode); $this->assertNull($termSignal); $this->assertFalse($process->isRunning()); $this->assertSame(0, $process->getExitCode()); $this->assertNull($process->getTermSignal()); $this->assertFalse($process->isTerminated()); }
protected function queueProcess() { if (!$this->benchmarks->valid()) { return; } $b = $this->benchmarks->current(); $this->benchmarks->next(); $key = serialize([$b->benchmark, $b->subbenchmark, $b->count]); if (!isset($this->stdout[$key])) { $this->stdout[$key] = ''; } if (!isset($this->runtimes[$key])) { $this->runtimes[$key] = []; } $current_process_id = $this->process_id; $this->process_id++; $this->processes[$current_process_id] = $process = new Process($b->command); $start = null; $process->on('exit', function ($code, $signal) use($b, $key, &$current_process_id, &$start) { $this->runtimes[$key][] = microtime(true) - $start; $this->output->writeln('<comment>End ' . $b->benchmark . '-' . $b->subbenchmark . ' ' . $b->count . ' #' . $b->execution . '</comment>'); unset($this->processes[$current_process_id]); $this->queueProcess(); }); $this->loop->addTimer(0.001, function ($timer) use($process, $key, $b, &$start) { $this->output->writeln('<comment>Start ' . $b->benchmark . '-' . $b->subbenchmark . ' ' . $b->count . ' #' . $b->execution . '</comment>'); $start = microtime(true); $process->start($timer->getLoop()); $process->stdout->on('data', function ($data) use(&$stdout, $key) { $this->stdout[$key] .= $data; }); }); }
protected function generateProcessOrSkipGeneration(LmStateDto $receivedControlDto) { $processesNumber = count($this->processes); if ($processesNumber < $this->tasks && ($this->processManagerDto->getMaxSimultaneousProcesses() > 1 ? $processesNumber < $this->processManagerDto->getMaxSimultaneousProcesses() : true)) { $this->logger->info("PM come to create new process."); $this->logger->info("Tasks number:" . serialize($this->tasks)); $this->logger->info("Processes number:" . serialize(count($this->processes))); $workerProcess = new Process($this->processManagerDto->getWorkerProcessCommand()); $workerProcess->start($this->loop); $workerProcessPid = $workerProcess->getPid(); //to protect from bug of proc_get_status if (!is_null($workerProcessPid)) { if ($this->processManagerDto->getPerformerSocketsParams()) { $workerProcess->stdin->write(json_encode($this->getPreparedSocketParams())); } $workerProcess->stdout->on(EventsConstants::DATA, function ($data) use(&$workerProcessPid) { //$data = @json_decode($data); //$this->logger->warning("Worker STDOUT: " . serialize($data)); }); $workerProcess->on(EventsConstants::PROCESS_EXIT, function ($exitCode, $termSignal) { $this->logger->warning("Worker sub-process exit with code: " . serialize($exitCode) . " | and term signal: " . serialize($termSignal)); }); $processDto = $this->getProcessDto($workerProcessPid); $this->processes[$workerProcessPid] = $workerProcess; $this->dtoContainer->setDto($processDto); } else { $this->dtoContainer->setDto(new PmStateDto()); } } else { //all processes already created, but not finished yet if (!$this->allTasksCreated) { $this->allTasksCreated = true; } $pmStateDto = new PmStateDto(); $pmStateDto->setAllProcessesCreated(true); $this->dtoContainer->setDto($pmStateDto); $this->logger->info("PM send all processes created."); $this->logger->info("Tasks number:" . serialize($this->tasks)); $this->logger->info("Processes number:" . count($this->processes)); } return null; }
/** * Runs the application * * @return void */ public function run() { if (!self::$defaultApplication) { self::$defaultApplication = $this; } $application = $this; if (OsDetector::isMacOS()) { $processName = './phpgui-i386-darwin'; $processPath = __DIR__ . '/../lazarus/phpgui-i386-darwin.app/Contents/MacOS/'; } elseif (OsDetector::isFreeBSD()) { $processName = './phpgui-x86_64-freebsd'; $processPath = __DIR__ . '/../lazarus/'; } elseif (OsDetector::isUnix()) { $processName = './phpgui-x86_64-linux'; $processPath = __DIR__ . '/../lazarus/'; } elseif (OsDetector::isWindows()) { $processName = '.\\phpgui-x86_64-win64'; $processPath = __DIR__ . '\\..\\lazarus\\'; } else { throw new RuntimeException('Operational System not identified by PHP-GUI.'); } $this->process = $process = new Process($processName, $processPath); $this->process->on('exit', function () use($application) { $application->loop->stop(); }); $this->receiver = $receiver = new Receiver($this); $this->sender = $sender = new Sender($this, $receiver); $this->loop->addTimer(0.001, function ($timer) use($process, $application, $receiver) { $process->start($timer->getLoop()); // We need to pause all default streams // The react/loop uses fread to read data from streams // On Windows, fread always is blocking // Stdin is paused, we use our own way to write on it $process->stdin->pause(); // Stdout is paused, we use our own way to read it $process->stdout->pause(); // Stderr is paused for avoiding fread $process->stderr->pause(); $process->stdout->on('data', function ($data) use($receiver) { $receiver->onData($data); }); $process->stderr->on('data', function ($data) { if (!empty($data)) { Output::err($data); } }); $application->running = true; // Bootstrap the application $application->fire('start'); }); $this->loop->addPeriodicTimer(0.001, function () use($application) { $application->sender->tick(); if (@is_resource($application->process->stdout->stream)) { $application->receiver->tick(); } }); $this->loop->run(); }