/** * Maintain the worker process map and notify the worker of an exited process. * @param bool $block When true, method will block waiting for an exit signal * @return void */ public function reap($block = false) { $map = $this->processes(); while (true) { $pid = pcntl_wait($status, $block === true && $this->daemon->is('parent') ? NULL : WNOHANG); if (!$pid || !isset($map[$pid])) { break; } $alias = $map[$pid]->group; $process = $this->processes[$alias][$pid]; $this->daemon->dispatch(array(Core_Daemon::ON_REAP), array($process, $status)); unset($this->processes[$alias][$pid]); // Keep track of process churn -- failures within a processes min_ttl // If too many failures of new processes occur inside a given interval, that's a problem. // Raise a fatal error to prevent runaway process forking which can be very damaging to a server if ($this->daemon->is('shutdown') || $process->runtime() >= $process->min_ttl) { continue; } foreach ($this->failures as $key => $failure_time) { if ($failure_time + self::CHURN_WINDOW < time()) { unset($this->failures[$key]); } } if (count($this->failures) > self::CHURN_LIMIT) { $this->daemon->fatal_error("Recently forked processes are continuously failing. See error log for additional details."); } } }
/** * Dispatch ON_ERROR event, write an error message to the event log, and restart the worker. * * Part of the Worker API - Use from your worker to log a fatal error message and restart the current process. * * @param $message * @return void */ public function fatal_error($message) { if ($this->daemon->is('parent')) { $this->daemon->fatal_error("Fatal Error: {$message}", $this->alias); } else { $this->daemon->fatal_error("Fatal Error: {$message}\nWorker process will restart", $this->alias); } }