protected function configureFuture(ExecFuture $future) { if ($this->getTimeout()) { $future->setTimeout($this->getTimeout()); } if ($this->getByteLimit()) { $future->setStdoutSizeLimit($this->getByteLimit()); $future->setStderrSizeLimit($this->getByteLimit()); } }
public function loadChangesetsForCommit($identifier) { $byte_limit = HeraldCommitAdapter::getEnormousByteLimit(); $time_limit = HeraldCommitAdapter::getEnormousTimeLimit(); $vcs = $this->getRepository()->getVersionControlSystem(); switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: // For git and hg, we can use normal commands. $drequest = DiffusionRequest::newFromDictionary(array('repository' => $this->getRepository(), 'user' => $this->getViewer(), 'commit' => $identifier)); $raw_diff = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest)->setTimeout($time_limit)->setByteLimit($byte_limit)->setLinesOfContext(0)->loadRawDiff(); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: // TODO: This diff has 3 lines of context, which produces slightly // incorrect "added file content" and "removed file content" results. // This may also choke on binaries, but "svnlook diff" does not support // the "--diff-cmd" flag. // For subversion, we need to use `svnlook`. $future = new ExecFuture('svnlook diff -t %s %s', $this->subversionTransaction, $this->subversionRepository); $future->setTimeout($time_limit); $future->setStdoutSizeLimit($byte_limit); $future->setStderrSizeLimit($byte_limit); list($raw_diff) = $future->resolvex(); break; default: throw new Exception(pht("Unknown VCS '%s!'", $vcs)); } if (strlen($raw_diff) >= $byte_limit) { throw new Exception(pht('The raw text of this change is enormous (larger than %d ' . 'bytes). Herald can not process it.', $byte_limit)); } if (!strlen($raw_diff)) { // If the commit is actually empty, just return no changesets. return array(); } $parser = new ArcanistDiffParser(); $changes = $parser->parseDiff($raw_diff); $diff = DifferentialDiff::newEphemeralFromRawChanges($changes); return $diff->getChangesets(); }
public function run() { if ($this->shouldRunSilently()) { echo "Running daemon '{$this->daemon}' silently. Use '--trace' or " . "'--verbose' to produce debugging output.\n"; } $root = phutil_get_library_root('phutil'); $root = dirname($root); $exec_dir = $root . '/scripts/daemon/exec/'; // NOTE: PHP implements proc_open() by running 'sh -c'. On most systems this // is bash, but on Ubuntu it's dash. When you proc_open() using bash, you // get one new process (the command you ran). When you proc_open() using // dash, you get two new processes: the command you ran and a parent // "dash -c" (or "sh -c") process. This means that the child process's PID // is actually the 'dash' PID, not the command's PID. To avoid this, use // 'exec' to replace the shell process with the real process; without this, // the child will call posix_getppid(), be given the pid of the 'sh -c' // process, and send it SIGUSR1 to keepalive which will terminate it // immediately. We also won't be able to do process group management because // the shell process won't properly posix_setsid() so the pgid of the child // won't be meaningful. // Format the exec command, which looks something like: // // exec ./exec_daemon DaemonName --trace -- --no-discovery $argv = array(); $argv[] = csprintf('exec ./exec_daemon.php %s', $this->daemon); foreach ($this->argv as $k => $arg) { $argv[] = csprintf('%s', $arg); } $argv[] = '--'; foreach ($this->moreArgs as $k => $arg) { $argv[] = csprintf('%s', $arg); } $command = implode(' ', $argv); while (true) { $this->logMessage('INIT', 'Starting process.'); $future = new ExecFuture('%C', $command); $future->setCWD($exec_dir); $future->setStdoutSizeLimit($this->captureBufferSize); $future->setStderrSizeLimit($this->captureBufferSize); $this->deadline = time() + $this->deadlineTimeout; $this->heartbeat = time() + self::HEARTBEAT_WAIT; $future->isReady(); $this->childPID = $future->getPID(); do { do { if ($this->traceMemory) { $memuse = number_format(memory_get_usage() / 1024, 1); $this->logMessage('RAMS', 'Overseer Memory Usage: ' . $memuse . ' KB'); } // We need a shortish timeout here so we can run the tick handler // frequently in order to process signals. $result = $future->resolve(1); list($stdout, $stderr) = $future->read(); $stdout = trim($stdout); $stderr = trim($stderr); if (strlen($stdout)) { $this->logMessage('STDO', $stdout); } if (strlen($stderr)) { $this->logMessage('STDE', $stderr); } $future->discardBuffers(); if ($result !== null) { list($err) = $result; if ($err) { $this->logMessage('FAIL', 'Process exited with error ' . $err . '.', $err); } else { $this->logMessage('DONE', 'Process exited successfully.'); } break 2; } if ($this->heartbeat < time()) { $this->heartbeat = time() + self::HEARTBEAT_WAIT; $this->dispatchEvent(self::EVENT_DID_HEARTBEAT); } } while (time() < $this->deadline); $this->logMessage('HANG', 'Hang detected. Restarting process.'); $this->annihilateProcessGroup(); } while (false); if ($this->inGracefulShutdown) { // If we just exited because of a graceful shutdown, break now. break; } $this->logMessage('WAIT', 'Waiting to restart process.'); sleep(self::RESTART_WAIT); if ($this->inGracefulShutdown) { // If we were awakend by a graceful shutdown, break now. break; } } // This is a clean exit after a graceful shutdown. $this->dispatchEvent(self::EVENT_WILL_EXIT); exit(0); }
public function run() { if ($this->shouldRunSilently()) { echo "Running daemon '{$this->daemon}' silently. Use '--trace' or " . "'--verbose' to produce debugging output.\n"; } $root = phutil_get_library_root('phutil'); $root = dirname($root); $exec_dir = $root . '/scripts/daemon/exec/'; // NOTE: PHP implements proc_open() by running 'sh -c'. On most systems this // is bash, but on Ubuntu it's dash. When you proc_open() using bash, you // get one new process (the command you ran). When you proc_open() using // dash, you get two new processes: the command you ran and a parent // "dash -c" (or "sh -c") process. This means that the child process's PID // is actually the 'dash' PID, not the command's PID. To avoid this, use // 'exec' to replace the shell process with the real process; without this, // the child will call posix_getppid(), be given the pid of the 'sh -c' // process, and send it SIGUSR1 to keepalive which will terminate it // immediately. We also won't be able to do process group management because // the shell process won't properly posix_setsid() so the pgid of the child // won't be meaningful. $exec_daemon = './exec_daemon.php'; $argv = $this->argv; array_unshift($argv, 'exec', $exec_daemon, $this->daemon); foreach ($argv as $k => $arg) { $argv[$k] = escapeshellarg($arg); } $command = implode(' ', $argv); while (true) { $this->logMessage('INIT', 'Starting process.'); $future = new ExecFuture($command); $future->setCWD($exec_dir); $future->setStdoutSizeLimit($this->captureBufferSize); $future->setStderrSizeLimit($this->captureBufferSize); $this->deadline = time() + $this->deadlineTimeout; $this->heartbeat = time() + self::HEARTBEAT_WAIT; $future->isReady(); $this->childPID = $future->getPID(); do { do { if ($this->traceMemory) { $memuse = number_format(memory_get_usage() / 1024, 1); $this->logMessage('RAMS', 'Overseer Memory Usage: ' . $memuse . ' KB'); } // We need a shortish timeout here so we can run the tick handler // frequently in order to process signals. $result = $future->resolve(1); list($stdout, $stderr) = $future->read(); $stdout = trim($stdout); $stderr = trim($stderr); if (strlen($stdout)) { $this->logMessage('STDO', $stdout, $stdout); } if (strlen($stderr)) { $this->logMessage('STDE', $stderr, $stderr); } $future->discardBuffers(); if ($result !== null) { list($err) = $result; if ($err) { $this->logMessage('FAIL', 'Process exited with error ' . $err . '.', $err); } else { $this->logMessage('DONE', 'Process exited successfully.'); } break 2; } if ($this->heartbeat < time()) { $this->heartbeat = time() + self::HEARTBEAT_WAIT; if ($this->conduitURI) { try { $this->conduit = new ConduitClient($this->conduitURI); $this->conduit->callMethodSynchronous('daemon.setstatus', array('daemonLogID' => $this->daemonLogID, 'status' => 'run')); } catch (Exception $ex) { } } } } while (time() < $this->deadline); $this->logMessage('HANG', 'Hang detected. Restarting process.'); $this->annihilateProcessGroup(); } while (false); $this->logMessage('WAIT', 'Waiting to restart process.'); sleep($this->restartDelay); } }
protected final function launch() { $console = PhutilConsole::getConsole(); if ($this->debug) { $console->writeOut("%s\n", pht('Starting Aphlict server in foreground...')); } else { Filesystem::writeFile($this->getPIDPath(), getmypid()); } $command = $this->getStartCommand($this->getServerArgv()); if (!$this->debug) { declare (ticks=1); pcntl_signal(SIGINT, array($this, 'cleanup')); pcntl_signal(SIGTERM, array($this, 'cleanup')); } register_shutdown_function(array($this, 'cleanup')); if ($this->debug) { $console->writeOut("%s\n\n \$ %s\n\n", pht('Launching server:'), $command); $err = phutil_passthru('%C', $command); $console->writeOut(">>> %s\n", pht('Server exited!')); exit($err); } else { while (true) { global $g_future; $g_future = new ExecFuture('exec %C', $command); // Discard all output the subprocess produces: it writes to the log on // disk, so we don't need to send the output anywhere and can just // throw it away. $g_future->setStdoutSizeLimit(0)->setStderrSizeLimit(0); $g_future->resolve(); // If the server exited, wait a couple of seconds and restart it. unset($g_future); sleep(2); } } }