protected function setUp() { $this->logger = $this->getMockBuilder(LoggerInterface::class)->setMethods(['info', 'warning'])->getMockForAbstractClass(); $this->connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->setMethods(['isServiceListening'])->getMock(); $this->pheanstalk = $this->getMockBuilder(PheanstalkInterface::class)->setMethods(['getConnection'])->getMockForAbstractClass(); $this->pheanstalk->expects($this->any())->method('getConnection')->will($this->returnValue($this->connection)); }
/** * {@inheritdoc} */ public function dequeue(SerializerInterface $serializer) { $job = $this->client->reserve(); if ($job) { return new BeanstalkdJob($this->client, $job, $serializer); } return null; }
private function doClear($tubeName, $state) { try { while ($item = $this->pheanstalk->{'peek' . $state}($tubeName)) { $this->pheanstalk->delete($item); } } catch (ServerException $e) { } }
public function testDone() { $jobId = 12345; $this->pheanstalkMock->expects($this->once())->method('delete')->with($this->callback(function (Job $job) use($jobId) { return $job->getId() === $jobId; })); $this->pheanstalkMock->expects($this->any())->method('peek')->with($jobId)->willReturn(new Job($jobId, 'asdf')); $this->loggerMock->expects($this->once())->method('info')->with('Done job (12345): asdf'); $this->sut->done($jobId); }
/** * Initializes the queue object * * @param \Pheanstalk\PheanstalkInterface $client Client object * @param string $queue Message queue name * @throws \Aimeos\MW\MQueue\Exception */ public function __construct(\Pheanstalk\PheanstalkInterface $client, $queue, $timeout = null) { try { $client->useTube($queue)->watch($queue); } catch (\Exception $e) { throw new \Aimeos\MW\MQueue\Exception($e->getMessage()); } $this->client = $client; $this->queue = $queue; $this->timeout = $timeout; }
private function writeTubeStats(PheanstalkInterface $conn, $tube, OutputInterface $out) { try { $stats = $conn->statsTube($tube); $out->writeln("<info>{$tube} Stats</info>"); $this->writeStats($stats, $out); } catch (ServerException $e) { if (false !== stripos($e->getMessage(), 'NOT_FOUND')) { return $out->writeln(sprintf('<error>Tube "%s" not found</error>', $tube)); } throw $e; } }
/** * {@inheritdoc} */ public function fail($queueName, Envelope $env) { try { $this->conn->bury($this->assurePheanstalkEnvelope($env)->getJob(), $this->options['fail-priority']); } catch (\Pheanstalk\Exception $e) { throw PheanstalkError::fromException($e); } }
/** * {@inheritDoc} */ public function watchOnly($tube) { if ($this->dispatcher) { $this->dispatcher->dispatch(CommandEvent::WATCH_ONLY, new CommandEvent($this, ['tube' => $tube])); } $this->pheanstalk->watchOnly($tube); return $this; }
/** * Watch for jobs on the given tube * * @return void */ public function watchForJobs() { // Time the worker will retire $retireTime = time() + $this->ttl; if (null !== $this->tube) { $this->pheanstalk->watchOnly($this->tube); } // Watch the Queue while (!$this->isTerminated()) { $job = $this->pheanstalk->reserve(5); if ($job) { // Let everyone know we just grabbed a job off the queue $this->output->writeln('<comment>Found Job ID: ' . $job->getId() . '</comment>'); // Check the data is valid for us to process a job if (!$this->isValid($job)) { $this->output->writeln('<comment>Invalid Job, skipping.</comment>'); $outcome = self::ACTION_BURY; } else { // Output to let anyone watching know that we're starting a worker $this->output->writeln('<comment>' . $this->getStartMessage($job) . '</comment>'); try { // Process the job $outcome = $this->processJob($job); } catch (\Exception $e) { // Output error $this->output->writeln('<error>Fatal Error: ' . $e->getMessage() . '</error>'); // Bury the job $this->pheanstalk->bury($job); // Break out of while loop break; } // Let the folks know we've completed it $this->output->writeln('<comment>Job Processed.</comment>'); } switch ($outcome) { case self::ACTION_DELETE: // Remove the job from the queue $this->pheanstalk->delete($job); break; case self::ACTION_BURY: // Remove the job from the queue $this->pheanstalk->bury($job); break; case self::ACTION_RELEASE: // Remove the job from the queue $this->pheanstalk->release($job); break; } $this->output->writeln('<info>Waiting for next job...</info>'); } // Check if it's time to retire the worker if (0 !== $this->ttl && time() > $retireTime) { $this->retire(); } } $this->output->writeln('<info>Exiting.</info>'); }
public function getTubeStats() { $result = []; $tubes = $this->pheanstalk->listTubes(); foreach ($tubes as $tubeName) { $stats = $this->pheanstalk->statsTube($tubeName); $result[] = ['name' => $tubeName, 'buried' => $stats['current-jobs-buried'], 'delayed' => $stats['current-jobs-delayed'], 'ready' => $stats['current-jobs-ready'], 'reserved' => $stats['current-jobs-reserved'], 'urgent' => $stats['current-jobs-urgent'], 'waiting' => $stats['current-waiting'], 'total' => $stats['total-jobs']]; } return $result; }
/** * {@inheritdoc} */ public function fail($queueName, Envelope $env) { if (!$env instanceof PheanstalkEnvelope) { throw new InvalidEnvelope(sprintf('%s requires that envelopes be instances of "%s", got "%s"', __CLASS__, PheanstalkEnvelope::class, get_class($env))); } try { $this->conn->bury($env->getJob(), $this->options['fail-priority']); } catch (\Pheanstalk\Exception $e) { throw PheanstalkError::fromException($e); } }
/** * Delete given job and create new job with old or passed params * * @param int $jobId * @param int $priority * @param int $delay */ public function reschedule($jobId, $priority = NULL, $delay = NULL) { /** @var Job $job */ $job = $this->pheanstalk->peek($jobId); $jobStats = $this->pheanstalk->statsJob($job); $this->pheanstalk->useTube($this->tube); $priority = NULL === $priority ? $jobStats['pri'] : $priority; $delay = NULL === $delay ? $jobStats['delay'] : $delay; $newJobId = $this->pheanstalk->put($job->getData(), $priority, $delay, $jobStats['ttr']); $this->pheanstalk->delete($job); $context = ['job_id' => $newJobId, 'old_job_id' => $jobId, 'text' => $job->getData(), 'priority' => $priority, 'delay' => $delay]; $this->logger->info(sprintf('Reschedule job (%d => %d): %s', $jobId, $newJobId, $job->getData()), $context); }
public function testExecuteJobAndNoMoreRetries() { $action = 'test'; $executor = $this->getMockForAbstractClass(ExecutorInterface::class); $executor->expects($this->any())->method('getName')->will($this->returnValue($action)); $this->manager->addExecutor($executor); $data = []; $job = new Job(1234, json_encode($data)); $stats = ['tube' => $action, 'releases' => 2, 'pri' => PheanstalkInterface::DEFAULT_PRIORITY]; $this->pheanstalk->expects($this->once())->method('statsJob')->with($job)->will($this->returnValue($stats)); $this->pheanstalk->expects($this->once())->method('bury')->with($job); $executor->expects($this->once())->method('execute')->will($this->throwException(new \Exception('oh noes!'))); $this->manager->executeJob($job); }
/** * @param Job $job The job to process * @param int $maxRetries The number of retries for this job * * @throws AbortException * * @return bool|mixed The executor result if successful, false otherwise */ public function executeJob(Job $job, $maxRetries = 1) { $this->dispatcher->dispatch(WorkerEvents::EXECUTE_JOB, new JobEvent($job)); $stats = $this->pheanstalk->statsJob($job); $payload = (array) json_decode($job->getData(), true); $releases = intval($stats['releases']); $priority = intval($stats['pri']); // context for logging $context = ['tube' => $stats['tube'], 'payload' => $payload, 'attempt' => $releases + 1]; try { // execute command $result = $this->execute($stats['tube'], $payload); // delete job if it completed without exceptions $this->delete($job); return $result; } catch (RescheduleException $re) { // reschedule the job $this->reschedule($job, $re->getRescheduleDate(), $priority); } catch (AbortException $e) { // abort thrown from executor, rethrow it and let the caller handle it throw $e; } catch (\Exception $e) { // some other exception occured $message = sprintf('Exception occurred: %s in %s on line %d', $e->getMessage(), $e->getFile(), $e->getLine()); $this->logJob($job->getId(), $message, LogLevel::ERROR, $context); $this->logJob($job->getId(), $e->getTraceAsString(), LogLevel::DEBUG, $context); // see if we have any retries left if ($releases > $maxRetries) { // no more retries, bury job for manual inspection $this->bury($job); $this->dispatcher->dispatch(WorkerEvents::JOB_BURIED_EVENT, new JobBuriedEvent($job, $e, $releases)); } else { // try again, regardless of the error $this->reschedule($job, new \DateTime('+10 minutes'), $priority); } } return false; }
/** * {@inheritdoc} */ public function delete() { return $this->client->delete($this->job); }
/** * Get the next job ready and buried in the specified tube and connection. * * @param PheanstalkInterface $pheanstalk * @param string $tubeName */ private function fetchJobs(PheanstalkInterface $pheanstalk, $tubeName) { try { $nextJobReady = $pheanstalk->peekReady($tubeName); $this->data['jobs'][$tubeName]['ready'] = ['id' => $nextJobReady->getId(), 'data' => $nextJobReady->getData()]; } catch (ServerException $e) { } try { $nextJobBuried = $pheanstalk->peekBuried($tubeName); $this->data['jobs'][$tubeName]['buried'] = ['id' => $nextJobBuried->getId(), 'data' => $nextJobBuried->getData()]; } catch (ServerException $e) { } }
public function buryJob($queueName, JobInterface $job) { $this->pheanstalk->bury(new Job($job->getData()['_beanstalk_id'], [])); }
public function put(CommandInterface $command) { $this->pheanstalk->put(serialize($command)); }
/** * {@inheritdoc} * * @param integer|null $priority */ public function release(ManagerInterface $manager, $delay = 0, $priority = PheanstalkInterface::DEFAULT_PRIORITY) { $this->pheanstalk->release($manager->getPheanstalkJob(), $priority, $delay); return true; }
/** * Mark a job as failed * * @access public * @param Job $job * @return $this */ public function failed(Job $job) { $beanstalkJob = new BeanstalkJob($job->getId(), $job->serialize()); $this->beanstalk->bury($beanstalkJob); return $this; }