/** @internal */ public function go(Process $process) { $this->deferred = $deferred = new Deferred(); $this->process = $process; $buffered = null; $process->stdout->on('data', function ($data) use(&$buffered) { if ($data !== '') { $buffered .= $data; } }); $process->on('exit', function ($code) use($deferred) { if ($code !== 0) { $deferred->reject($code); } else { $deferred->resolve(); } }); $that = $this; $this->promise = $deferred->promise()->then(function () use(&$buffered, $that) { if ($buffered === null) { $buffered = true; } else { $buffered = $that->parseValue(trim($buffered)); } return $buffered; }); }
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(); }
/** * @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()); }
/** * 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 close() { if ($this->out !== null) { $this->out->removeAllListeners(); } if ($this->in !== null) { $this->in->removeAllListeners(); } if ($this->err !== null) { $this->err->removeAllListeners(); } $this->process->removeAllListeners(); if ($this->process->isRunning()) { $this->process->terminate(); } }
/** * @param Process $process * @return null * @throws CommandsExecutionException */ public static function tryTerminateProcess(Process $process) { try { $terminationResult = $process->terminate(); if (!$terminationResult) { throw new CommandsExecutionException("Process termination for PID " . $process->getPid() . " wasn't success"); } } catch (\Exception $e) { try { self::sendSig($process->getPid(), SIGKILL); } catch (\Exception $e) { throw new CommandsExecutionException("SIGKILL for PID " . $process->getPid() . " wasn't success"); } } return null; }
public function __construct($host = '127.0.0.1', $docroot = null, $router = null, $php = PHP_BINARY) { $port = mt_rand(49152, 65535); $command = implode(' ', array_filter([escapeshellarg($php), '-S', escapeshellarg("{$host}:{$port}"), $docroot !== null ? '-t ' . escapeshellarg($docroot) : null, $router !== null ? escapeshellarg($router) : null], 'is_string')); parent::__construct($command, null, null, ['bypass_shell' => true]); $this->host = $host; $this->port = $port; }
/** * Promise that resolves once child process exits * * @param LoopInterface $loop ReactPHP event loop. * @param Process $process Child Process to run. * * @return \React\Promise\PromiseInterface */ function childProcessPromise(LoopInterface $loop, Process $process) { $deferred = new Deferred(); $buffers = ['stderr' => '', 'stdout' => '']; $process->on('exit', function ($exitCode) use($deferred, &$buffers) { $deferred->resolve(new ProcessOutcome($exitCode, $buffers['stderr'], $buffers['stdout'])); }); \WyriHaximus\React\futurePromise($loop, $process)->then(function (Process $process) use($loop, &$buffers) { $process->start($loop); $process->stderr->on('data', function ($output) use(&$buffers) { $buffers['stderr'] .= $output; }); $process->stdout->on('data', function ($output) use(&$buffers) { $buffers['stdout'] .= $output; }); }); return $deferred->promise(); }
/** * @return PromiseInterface */ public function execute($program = '') { if ($program === '') { return new RejectedPromise(); } $deferred = new Deferred(); $process = new Process('exec hash ' . $program); $process->on('exit', function ($exitCode) use($deferred) { if ($exitCode == 0) { $deferred->resolve(); return; } $deferred->reject(); }); \WyriHaximus\React\futurePromise($this->loop, $process)->then(function (Process $process) { $process->start($this->loop); }); return $deferred->promise(); }
/** * @return PromiseInterface */ public function execute() { $deferred = new Deferred(); $buffer = ''; $process = new Process('exec nproc'); $process->on('exit', function ($exitCode) use($deferred, &$buffer) { if ($exitCode == 0) { $deferred->resolve($buffer); return; } $deferred->reject(); }); \WyriHaximus\React\futurePromise($this->loop, $process)->then(function (Process $process) use(&$buffer) { $process->start($this->loop); $process->stdout->on('data', function ($output) use(&$buffer) { $buffer += $output; }); }); return $deferred->promise(); }
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]; }
/** * */ 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(); }
/** * {@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); }
/** * @return null * @throws \CommandsExecutor\Inventory\Exceptions\CommandsExecutionException */ protected function stopReplyStack() { LinuxCommands::sendSigTermOrKill($this->commandsManager->getPidByPpid($this->replyStackProcess->getPid())->getPid()); LinuxCommands::tryTerminateProcess($this->replyStackProcess); 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); }
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; }); }); }
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()); }
/** * 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(); }
public function tryTerminateProcess(Process $process) { try { $terminationResult = $process->terminate(); if (!$terminationResult) { throw new ReactManagerException("Process termination for PID " . $process->getPid() . " wasn't success"); } } catch (\Exception $e) { try { $this->logAndSendSigKill($process->getPid(), $e); } catch (\Exception $e) { $this->logger->warning("Parent process can't be sigKilled."); } } return null; }