*/ class Queue implements QueueInterface, TaskLogAwareInterface { use LoggerAwareTrait; use ServiceLocatorAwareTrait; use TaskLogAwareTrait; use LockTrait; const LOCK_PREFIX = 'taskqueue_lock_'; private $name; /** * @var QueueBrokerInterface|ServiceLocatorAwareInterface */ private $broker; /** * @var int */ private $weight; /** * @param string $name * @param QueueBrokerInterface $broker * @param int $weight */ public function __construct($name, QueueBrokerInterface $broker, $weight = 1) { if (empty($name)) { throw new \InvalidArgumentException("Queue name needs to be set."); } $this->name = $name; $this->setWeight($weight); $this->setBroker($broker); } /** * @inheritdoc */ public function __toString() { return $this->getName(); } /** * @inheritdoc */ public function __toPhpCode() { return 'new ' . get_called_class() . '(' . \common_Utils::toHumanReadablePhpString($this->name) . ', ' . \common_Utils::toHumanReadablePhpString($this->broker) . ', ' . \common_Utils::toHumanReadablePhpString($this->weight) . ')'; } /** * @inheritdoc */ public function initialize() { $this->getBroker()->createQueue(); } /** * @inheritdoc */ public function getName() { return $this->name; } /** * @param int $weight * * @return Queue */ public function setWeight($weight) { $this->weight = abs($weight); return $this; } /** * @inheritdoc */ public function getWeight() { return $this->weight; } /** * @inheritdoc */ public function setBroker(QueueBrokerInterface $broker) { $this->broker = $broker; $this->broker->setQueueName($this->getName()); return $this; } public function getBroker(): QueueBrokerInterface { $this->broker->setServiceLocator($this->getServiceLocator()); return $this->broker; } /** * @inheritdoc */ public function enqueue(TaskInterface $task, $label = null) { try { if (!is_null($label)) { $task->setLabel($label); } $lock = $this->createLock(self::LOCK_PREFIX . $task->getId()); $lock->acquire(true); $isEnqueued = $this->getBroker()->push($task); if ($isEnqueued) { $this->getTaskLog() ->add($task, TaskLogInterface::STATUS_ENQUEUED, $label); } return $isEnqueued; } catch (\Exception $e) { $this->logError('Enqueueing ' . $task . ' failed with MSG: ' . $e->getMessage()); } finally { $lock->release(); } return false; } /** * @inheritdoc */ public function dequeue() { $task = $this->getBroker()->pop(); if (!$task) { return null; } $lock = $this->createLock(self::LOCK_PREFIX . $task->getId()); $lock->acquire(true); if ($this->canDequeueTask($task)) { $this->getTaskLog()->setStatus($task->getId(), TaskLogInterface::STATUS_DEQUEUED); $this->logInfo(sprintf('Task %s has been dequeued', $task->getId()), $this->getLogContext()); } $lock->release(); return $task; } /** * @inheritdoc */ public function acknowledge(TaskInterface $task) { $this->getBroker()->delete($task); } /** * Count of messages in the queue. * * @return int */ public function count() { return $this->getBroker()->count(); } /** * @return bool */ public function isSync() { return $this->broker instanceof SyncQueueBrokerInterface; } /** * @inheritdoc */ public function getNumberOfTasksToReceive() { return $this->getBroker()->getNumberOfTasksToReceive(); } /** * @param TaskInterface $task * * @return bool */ protected function canDequeueTask(TaskInterface $task) { return $this->getTaskLog()->getStatus($task->getId()) != TaskLogInterface::STATUS_CANCELLED; } /** * @return array */ protected function getLogContext() { return [ 'PID' => getmypid(), 'QueueName' => $this->getName(), ]; } }