/** * Seperate the job from the worker via pcntl_fork * * @param Job $job */ public function perform(Job $job) { $this->child = Resque::fork(); // Forked and we're the child. Run the job. if ($this->child === 0) { parent::perform($job); exit(0); } // Parent process, sit and wait if ($this->child > 0) { $status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); $this->worker->updateProcLine($status); $this->worker->log($status); // Wait until the child process finishes before continuing pcntl_wait($status); $exitStatus = pcntl_wexitstatus($status); if ($exitStatus !== 0) { $job->fail(new Job\DirtyExitException('Job exited with exit code ' . $exitStatus)); } } $this->child = null; }
/** * The primary loop for a worker which when called on an instance starts * the worker's life cycle. * * Queues are checked every $interval (seconds) for new jobs. * * @param int $interval How often to check for new jobs across the queues. */ public function work($interval = Resque::DEFAULT_INTERVAL, $blocking = false) { $this->updateProcLine('Starting'); $this->startup(); while (true) { if ($this->shutdown) { break; } // Attempt to find and reserve a job $job = false; if (!$this->paused) { if ($blocking === true) { $this->logger->log(LogLevel::INFO, 'Starting blocking with timeout of {interval}', array('interval' => $interval)); $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with blocking timeout ' . $interval); } else { $this->updateProcLine('Waiting for ' . implode(',', $this->queues) . ' with interval ' . $interval); } $job = $this->reserve($blocking, $interval); } if (!$job) { // For an interval of 0, break now - helps with unit testing etc if ($interval == 0) { break; } if ($blocking === false) { // If no job was found, we sleep for $interval before continuing and checking again $this->logger->log(LogLevel::INFO, 'Sleeping for {interval}', array('interval' => $interval)); if ($this->paused) { $this->updateProcLine('Paused'); } else { $this->updateProcLine('Waiting for ' . implode(',', $this->queues)); } usleep($interval * 1000000); } continue; } $this->logger->log(LogLevel::NOTICE, 'Starting work on {job}', array('job' => $job)); Event::trigger('beforeFork', $job); $this->workingOn($job); $this->child = Resque::fork(); // Forked and we're the child. Run the job. if ($this->child === 0 || $this->child === false) { $status = 'Processing ' . $job->queue . ' since ' . strftime('%F %T'); $this->updateProcLine($status); $this->logger->log(LogLevel::INFO, $status); $this->perform($job); if ($this->child === 0) { exit(0); } } if ($this->child > 0) { // Parent process, sit and wait $status = 'Forked ' . $this->child . ' at ' . strftime('%F %T'); $this->updateProcLine($status); $this->logger->log(LogLevel::INFO, $status); // Wait until the child process finishes before continuing pcntl_wait($status); $exitStatus = pcntl_wexitstatus($status); if ($exitStatus !== 0) { $job->fail(new DirtyExitException('Job exited with exit code ' . $exitStatus)); } } $this->child = null; $this->doneWorking(); } $this->unregisterWorker(); }