/** * * @param string $affix * @param bool $removeOld * @return string */ protected function getSockFile($affix, $removeOld) { if (Utils::isWindows()) { //we have no unix domain sockets support return '127.0.0.1'; } //since all commands set setcwd() we can make sure we are in the current application folder if ('/' === substr($this->socketPath, 0, 1)) { $run = $this->socketPath; } else { $run = getcwd() . '/' . $this->socketPath; } if ('/' !== substr($run, -1)) { $run .= '/'; } if (!is_dir($run) && !mkdir($run, 0777, true)) { throw new \RuntimeException(sprintf('Could not create %s folder.', $run)); } $sock = $run . $affix . '.sock'; if ($removeOld && file_exists($sock)) { unlink($sock); } return 'unix://' . $sock; }
/** * Creates a new ProcessSlave instance. * * @param integer $port */ protected function newInstance($port) { if ($this->inShutdown) { //when we are in the shutdown phase, we close all connections //as a result it actually tries to reconnect the slave, but we forbid it in this phase. return; } $keepClosed = false; $bootstrapFailed = 0; if (isset($this->slaves[$port])) { $bootstrapFailed = $this->slaves[$port]['bootstrapFailed']; $keepClosed = $this->slaves[$port]['keepClosed']; if ($keepClosed) { return; } } if ($this->output->isVeryVerbose()) { $this->output->writeln(sprintf("Start new worker #%d", $port)); } $host = Utils::isWindows() ? 'tcp://127.0.0.1' : $this->getNewSlaveSocket($port); $slave = ['ready' => false, 'pid' => null, 'port' => $port, 'closeWhenFree' => false, 'waitForRegister' => true, 'duringBootstrap' => false, 'bootstrapFailed' => $bootstrapFailed, 'keepClosed' => $keepClosed, 'busy' => false, 'requests' => 0, 'connections' => 0, 'connection' => null, 'host' => $host]; $bridge = var_export($this->getBridge(), true); $bootstrap = var_export($this->getAppBootstrap(), true); $config = ['port' => $slave['port'], 'host' => $slave['host'], 'session_path' => session_save_path(), 'controllerHost' => Utils::isWindows() ? 'tcp://127.0.0.1' : $this->controllerHost, 'app-env' => $this->getAppEnv(), 'debug' => $this->isDebug(), 'logging' => $this->isLogging(), 'static' => $this->isServingStatic()]; $config = var_export($config, true); $dir = var_export(__DIR__, true); $script = <<<EOF <?php set_time_limit(0); require_once file_exists({$dir} . '/vendor/autoload.php') ? {$dir} . '/vendor/autoload.php' : {$dir} . '/../../autoload.php'; require_once {$dir} . '/functions.php'; //global for all global functions \\PHPPM\\ProcessSlave::\$slave = new \\PHPPM\\ProcessSlave({$bridge}, {$bootstrap}, {$config}); \\PHPPM\\ProcessSlave::\$slave->run(); EOF; $commandline = $this->phpCgiExecutable; $file = tempnam(sys_get_temp_dir(), 'dbg'); file_put_contents($file, $script); register_shutdown_function('unlink', $file); //we can not use -q since this disables basically all header support //but since this is necessary at least in Symfony we can not use it. //e.g. headers_sent() returns always true, although wrong. $commandline .= ' -C ' . ProcessUtils::escapeArgument($file); $descriptorspec = [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']]; $this->slaves[$port] = $slave; $this->slaves[$port]['process'] = proc_open($commandline, $descriptorspec, $pipes); $stderr = new \React\Stream\Stream($pipes[2], $this->loop); $stderr->on('data', function ($data) use($port) { if ($this->lastWorkerErrorPrintBy !== $port) { $this->output->writeln("<info>--- Worker {$port} stderr ---</info>"); $this->lastWorkerErrorPrintBy = $port; } $this->output->write("<error>{$data}</error>"); }); $this->slaves[$port]['stderr'] = $stderr; }