tao-test/app/tao/models/classes/taskQueue/Queue.php

251 lines
5.9 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2017-2021 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
*
*/
namespace oat\tao\model\taskQueue;
use oat\oatbox\log\LoggerAwareTrait;
use oat\oatbox\mutex\LockTrait;
use oat\tao\model\taskQueue\Queue\Broker\QueueBrokerInterface;
use oat\tao\model\taskQueue\Queue\Broker\SyncQueueBrokerInterface;
use oat\tao\model\taskQueue\Task\TaskInterface;
use oat\tao\model\taskQueue\TaskLog\TaskLogAwareInterface;
use oat\tao\model\taskQueue\TaskLog\TaskLogAwareTrait;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorAwareTrait;
/**
* @author Gyula Szucs <gyula@taotesting.com>
*/
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(),
];
}
}