/** * Runs the worker in separate process. * * @param callable $callable * @param \Phalcon\Queue\Beanstalk\Job $job * @return boolean * @throws \RuntimeException */ private function spawn($callable, Job $job) { $pid = pcntl_fork(); switch ($pid) { case -1: throw new \RuntimeException('Fork failed, bailing'); break; case 0: // We're in the child process call_user_func($callable, $job); break; default: // Wait for success exit code — exit(0) pcntl_waitpid($pid, $status); $result = pcntl_wexitstatus($status); if ($result != 0) { // Something goes wrong return false; } else { // If everything is OK, delete the job from queue try { $job->delete(); } catch (\Exception $e) { if (null !== $this->logger) { $this->logger->warning(sprintf('Exception thrown when trying to delete job: %d — %s', $e->getCode(), $e->getMessage())); } } } break; } return true; }
/** * Runs the main worker cycle. * * @param boolean $ignoreErrors */ public function doWork($ignoreErrors = false) { declare (ticks=1); set_time_limit(0); # Check if we are using Fork1.0 (php < 7) if (class_exists('duncan3dc\\Helpers\\Fork')) { $fork = new \duncan3dc\Helpers\Fork(); $fork->ignoreErrors = $ignoreErrors; } else { $fork = new Fork(); } foreach ($this->workers as $tube => $worker) { $that = clone $this; // Run the worker in separate process. $fork->call(function () use($tube, $worker, $that, $fork, $ignoreErrors) { $that->connect(); do { $job = $that->reserveFromTube($tube); if ($job && $job instanceof Job) { $fork->call(function () use($worker, $job) { call_user_func($worker, $job); }); try { $fork->wait(); try { $job->delete(); } catch (\Exception $e) { if (null !== $this->logger) { $this->logger->warning(sprintf('Exception thrown while deleting the job: %d — %s', $e->getCode(), $e->getMessage())); } } } catch (\Exception $e) { if (null !== $this->logger) { $this->logger->warning(sprintf('Exception thrown while handling job #%s: %d — %s', $job->getId(), $e->getCode(), $e->getMessage())); } if (!$ignoreErrors) { return; } } } else { // There is no jobs so let's sleep to not increase CPU usage usleep(rand(7000, 10000)); } } while (true); exit(0); }); } try { $fork->wait(); } catch (ForkException $e) { if (!$ignoreErrors) { throw $e; } } }