Exemplo n.º 1
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.
     // 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);
 }
Exemplo n.º 2
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);
     }
 }