/** * {@inheritDoc} */ public function createCurrentProcess() { $process = new Process(); $process->setPidFromCurrentProcess(); return $process; }
/** * Work * * 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. @todo remove, use setInterval or similar */ public function work($interval = 3) { $this->startup(); while (true) { if ($this->shutdown) { break; } $this->getProcess()->dispatchSignals(); if ($this->paused) { $this->getProcess()->setTitle('Paused'); if ($interval == 0) { break; } usleep($interval * 1000000); continue; } try { $job = $this->reserve(); } catch (\Exception $ex) { $this->getLogger()->error('Failed to reserve due to exception "{message}", skipping', array('message' => $ex->getMessage())); continue; } if (null === $job) { // For an interval of 0, break now - helps with unit testing etc // @todo replace with some method, which can be mocked... an interval of 0 should be considered valid if ($interval == 0) { break; } $this->eventDispatcher->dispatch(ResqueWorkerEvents::WAIT_NO_JOB, new WorkerEvent($this)); $this->getProcess()->setTitle('Waiting for ' . implode(',', $this->queues)); $this->getLogger()->debug('Sleeping for {seconds}s, no jobs on {queues}', array('queues' => implode(', ', array_map(function ($a) { return $a->getName(); }, $this->getQueues())), 'seconds' => $interval)); sleep($interval); continue; } $this->getLogger()->notice('Starting work on {job}', array('job' => $job)); if ($job instanceof TrackableJobInterface) { $job->setState(JobInterface::STATE_PERFORMING); } $this->setCurrentJob($job); if ($this->fork) { $this->eventDispatcher->dispatch(ResqueWorkerEvents::BEFORE_FORK_TO_PERFORM, new WorkerJobEvent($this, $job)); $this->childProcess = $this->getProcess()->fork(); if (null === $this->childProcess) { // This is child process, it will perform the job and then die. $this->eventDispatcher->dispatch(ResqueWorkerEvents::AFTER_FORK_TO_PERFORM, new WorkerJobEvent($this, $job)); // @todo do not construct Process here. $child = new Process(); $child->setPidFromCurrentProcess(); $this->setProcess($child); $this->perform($job); exit(0); } else { // This is the parent. $title = 'Forked ' . $this->childProcess->getPid() . ' at ' . date('c'); $this->getProcess()->setTitle($title); $this->getLogger()->debug($title); // Wait until the child process finishes before continuing. $this->childProcess->wait(); if (false === $this->childProcess->isCleanExit()) { $exception = new DirtyExitException('Job dirty exited with code ' . $this->childProcess->getExitCode()); $this->handleFailedJob($job, $exception); } } // Child should be dead by now. $this->childProcess = null; } else { $this->perform($job); } $this->workComplete($job); } }