You've already forked ugly-queue
First round of updates finished.
- Needs better test cases.
This commit is contained in:
71
README.md
71
README.md
@@ -1,7 +1,7 @@
|
||||
ugly-queue
|
||||
==========
|
||||
|
||||
A simple file-based queue system for PHP 5.3.3+
|
||||
A simple file-based FIFO queue system for PHP 5.3.3+
|
||||
|
||||
Build statuses:
|
||||
- master: [](https://travis-ci.org/dcarbone/ugly-queue)
|
||||
@@ -20,15 +20,74 @@ Once installed, you must first initialize an instance of [src/UglyQueueManager.p
|
||||
This is done as such:
|
||||
|
||||
```php
|
||||
$config = array(
|
||||
'queue-base-dir' => 'path to where you would like queue files and directories to be stored'
|
||||
);
|
||||
$queueBaseDir = 'path to where you would like queue files and directories to be stored';
|
||||
|
||||
$manager = new UglyQueueManager($config);
|
||||
$manager = new UglyQueueManager($queueBaseDir);
|
||||
```
|
||||
|
||||
Once initialized, you can start adding queues!
|
||||
|
||||
```php
|
||||
$manager
|
||||
$sandwichQueue = $manager->createQueue('sandwiches');
|
||||
|
||||
$sandwichQueue->lock();
|
||||
|
||||
$sandwichQueue->addItems(array(
|
||||
'bread',
|
||||
'meat',
|
||||
'cheese',
|
||||
'lettuce',
|
||||
'bread'
|
||||
));
|
||||
|
||||
$sandwichQueue->unlock();
|
||||
```
|
||||
|
||||
Once you have items added to the queue, you can either pull items out ad-hoc or set up some sort of cron
|
||||
or schedule task to process items regularly.
|
||||
|
||||
If the base directory for all of your queues remains the same, each initialization
|
||||
of `UglyQueueManager` will automatically find and initialize instances of pre-existing
|
||||
UglyQueues.
|
||||
|
||||
In a subsequent request, simply do the following:
|
||||
|
||||
```php
|
||||
$queueBaseDir = 'path to where you would like queue files and directories to be stored';
|
||||
|
||||
$manager = new UglyQueueManager($queueBaseDir);
|
||||
|
||||
// 'tasty-sandwich' queue will exist now
|
||||
|
||||
$tastySandwich = $manager->getQueue('sandwiches');
|
||||
|
||||
$tastySandwich->lock();
|
||||
|
||||
// Specify the number of items you wish to retrieve from the queue
|
||||
|
||||
$items = $tastySandwich->retrieveItems(4);
|
||||
|
||||
// $items is now an array...
|
||||
|
||||
var_export($items);
|
||||
|
||||
/*
|
||||
array (
|
||||
4 => 'bread',
|
||||
3 => 'lettuce',
|
||||
2 => 'cheese',
|
||||
1 => 'meat',
|
||||
)
|
||||
*/
|
||||
|
||||
```
|
||||
|
||||
The queue will then retain a single item, `0 => 'bread'` as the 5th item left in the queue.
|
||||
|
||||
At any time you can determine how many items remain in a queue by executing `count($queueObj);`
|
||||
|
||||
There are a few limitations currently:
|
||||
|
||||
1. This lib is designed for small values without much in the way of formatting or line breaks
|
||||
2. It is designed to be atomic, meaning that only one process can be adding / retrieving items from
|
||||
a queue at a time. Reading actions (count, searching, etc) are NOT atomic, however.
|
||||
|
||||
@@ -68,39 +68,7 @@ class UglyQueue implements \Serializable, \SplSubject, \Countable
|
||||
$this->queueTmpFile = sprintf('%s%squeue.tmp', $path, DIRECTORY_SEPARATOR);
|
||||
$this->serializeFile = sprintf('%s%sugly-queue.obj', $path, DIRECTORY_SEPARATOR);
|
||||
|
||||
if (is_readable($this->path) && is_writable($this->path))
|
||||
$this->mode = self::QUEUE_READWRITE;
|
||||
else if (is_readable($this->path))
|
||||
$this->mode = self::QUEUE_READONLY;
|
||||
|
||||
if (!file_exists($this->path.'/index.html'))
|
||||
{
|
||||
if ($this->mode === self::QUEUE_READONLY)
|
||||
throw new \RuntimeException('Cannot initialize queue with name "'.$this->name.'", the user lacks permission to create files.');
|
||||
|
||||
$html = <<<HTML
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Directory access is forbidden.</p>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
file_put_contents($this->path.'/index.html', $html);
|
||||
}
|
||||
|
||||
if (!file_exists($this->queueFile))
|
||||
{
|
||||
if ($this->mode === self::QUEUE_READONLY)
|
||||
throw new \RuntimeException('Cannot initialize queue with name "'.$this->name.'", the user lacks permission to create files.');
|
||||
|
||||
file_put_contents($this->queueFile, '');
|
||||
}
|
||||
|
||||
$this->_notifyStatus = UglyQueueEnum::QUEUE_INITIALIZED;
|
||||
$this->notify();
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,6 +145,14 @@ HTML;
|
||||
return $this->serializeFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function isLocked()
|
||||
{
|
||||
return $this->locked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $ttl Time to live in seconds
|
||||
* @throws \InvalidArgumentException
|
||||
@@ -190,10 +166,8 @@ HTML;
|
||||
if ($ttl < 1)
|
||||
throw new \InvalidArgumentException('Argument 1 expected to be greater than 0 "'.$ttl.'" seen');
|
||||
|
||||
$alreadyLocked = $this->isLocked();
|
||||
|
||||
// If there is currently no lock
|
||||
if ($alreadyLocked === false)
|
||||
if ($this->isAlreadyLocked() === false)
|
||||
return $this->createLockFile($ttl);
|
||||
|
||||
// If we make it this far, there is already a lock in place.
|
||||
@@ -209,7 +183,7 @@ HTML;
|
||||
*/
|
||||
public function unlock()
|
||||
{
|
||||
if ($this->locked === true)
|
||||
if ($this->isLocked() === true)
|
||||
{
|
||||
unlink($this->lockFile);
|
||||
$this->locked = false;
|
||||
@@ -223,7 +197,7 @@ HTML;
|
||||
* @throws \RuntimeException
|
||||
* @return bool
|
||||
*/
|
||||
public function isLocked()
|
||||
public function isAlreadyLocked()
|
||||
{
|
||||
// First check for lock file
|
||||
if (is_file($this->lockFile))
|
||||
@@ -300,7 +274,7 @@ HTML;
|
||||
if ($i++ >= $start_line)
|
||||
{
|
||||
list ($key, $value) = $line;
|
||||
$data[$key] = $value;
|
||||
$data = array($key => $value) + $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,7 +323,7 @@ HTML;
|
||||
throw new \RuntimeException('Cannot add item to queue "'.$this->name.'" as it is in read-only mode');
|
||||
|
||||
// If we don't have a lock, assume issue and move on.
|
||||
if ($this->locked === false)
|
||||
if ($this->isLocked() === false)
|
||||
throw new \RuntimeException('Cannot add item to queue "'.$this->name.'". Queue is already locked by another process');
|
||||
|
||||
if (!is_resource($this->tmpHandle))
|
||||
@@ -368,6 +342,17 @@ HTML;
|
||||
."\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $items
|
||||
*/
|
||||
public function addItems(array $items)
|
||||
{
|
||||
foreach($items as $k=>$v)
|
||||
{
|
||||
$this->addItem($k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is a tmp queue file, add it's contents to the beginning of a new queue file
|
||||
*
|
||||
@@ -441,7 +426,17 @@ HTML;
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize(array($this->name, $this->path));
|
||||
return serialize(
|
||||
array(
|
||||
$this->baseDir,
|
||||
$this->name,
|
||||
$this->path,
|
||||
$this->queueFile,
|
||||
$this->queueTmpFile,
|
||||
$this->lockFile,
|
||||
$this->serializeFile,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,10 +449,15 @@ HTML;
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
/** @var \DCarbone\UglyQueue $uglyQueue */
|
||||
$data = unserialize($serialized);
|
||||
$this->name = $data[0];
|
||||
$this->path = $data[1];
|
||||
$this->baseDir = $data[0];
|
||||
$this->name = $data[1];
|
||||
$this->path = $data[2];
|
||||
$this->queueFile = $data[3];
|
||||
$this->queueTmpFile = $data[4];
|
||||
$this->lockFile = $data[5];
|
||||
$this->serializeFile = $data[6];
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -504,6 +504,26 @@ HTML;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is mostly intended to check the "validity" of a re-initialized queue
|
||||
*
|
||||
* Could probably stand to be improved.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function _valid()
|
||||
{
|
||||
return (
|
||||
$this->baseDir !== null &&
|
||||
$this->name !== null &&
|
||||
$this->path !== null &&
|
||||
$this->queueFile !== null &&
|
||||
$this->queueTmpFile !== null &&
|
||||
$this->lockFile !== null &&
|
||||
$this->serializeFile !== null
|
||||
);
|
||||
}
|
||||
|
||||
// --------
|
||||
|
||||
/**
|
||||
@@ -524,10 +544,51 @@ HTML;
|
||||
}
|
||||
|
||||
$this->locked = true;
|
||||
|
||||
$this->_notifyStatus = UglyQueueEnum::QUEUE_LOCKED;
|
||||
$this->notify();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-construct initialization method.
|
||||
*
|
||||
* Also used post-un-serialization
|
||||
*/
|
||||
protected function initialize()
|
||||
{
|
||||
if (is_readable($this->path) && is_writable($this->path))
|
||||
$this->mode = self::QUEUE_READWRITE;
|
||||
else if (is_readable($this->path))
|
||||
$this->mode = self::QUEUE_READONLY;
|
||||
|
||||
if (!file_exists($this->path.'/index.html'))
|
||||
{
|
||||
if ($this->mode === self::QUEUE_READONLY)
|
||||
throw new \RuntimeException('Cannot initialize queue with name "'.$this->name.'", the user lacks permission to create files.');
|
||||
|
||||
$html = <<<HTML
|
||||
<html>
|
||||
<head>
|
||||
<title>403 Forbidden</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Directory access is forbidden.</p>
|
||||
</body>
|
||||
</html>
|
||||
HTML;
|
||||
file_put_contents($this->path.'/index.html', $html);
|
||||
}
|
||||
|
||||
if (!file_exists($this->queueFile))
|
||||
{
|
||||
if ($this->mode === self::QUEUE_READONLY)
|
||||
throw new \RuntimeException('Cannot initialize queue with name "'.$this->name.'", the user lacks permission to create files.');
|
||||
|
||||
file_put_contents($this->queueFile, '');
|
||||
}
|
||||
|
||||
$this->_notifyStatus = UglyQueueEnum::QUEUE_INITIALIZED;
|
||||
$this->notify();
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,22 @@ class UglyQueueManager implements \SplObserver, \Countable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return UglyQueue|UglyQueueManager
|
||||
*/
|
||||
public function getQueue($name)
|
||||
{
|
||||
if (isset($this->queues[$name]))
|
||||
return $this->queues[$name];
|
||||
|
||||
$path = sprintf('%s/%s', $this->baseDir, $name);
|
||||
if (file_exists($path))
|
||||
return $this->addQueueAtPath($path);
|
||||
|
||||
return $this->createQueue($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UglyQueue $uglyQueue
|
||||
* @return \DCarbone\UglyQueueManager
|
||||
@@ -61,7 +77,8 @@ class UglyQueueManager implements \SplObserver, \Countable
|
||||
*/
|
||||
public function createQueue($name)
|
||||
{
|
||||
$this->addQueue(new UglyQueue($this->baseDir, $name, array($this)));
|
||||
$queue = new UglyQueue($this->baseDir, $name, array($this));
|
||||
$this->addQueue($queue);
|
||||
return end($this->queues);
|
||||
}
|
||||
|
||||
@@ -80,11 +97,15 @@ class UglyQueueManager implements \SplObserver, \Countable
|
||||
return null;
|
||||
|
||||
$serializedFile = sprintf('%s/%s/ugly-queue.obj', $this->baseDir, $queueName);
|
||||
/** @var \DCarbone\UglyQueue $uglyQueue */
|
||||
if (file_exists($serializedFile))
|
||||
$uglyQueue = unserialize(file_get_contents($serializedFile));
|
||||
else
|
||||
|
||||
if (!isset($uglyQueue) || $uglyQueue->_valid() === false)
|
||||
$uglyQueue = new UglyQueue($this->baseDir, $queueName, array($this));
|
||||
|
||||
$uglyQueue->attach($this);
|
||||
|
||||
return $this->addQueue($uglyQueue);
|
||||
}
|
||||
|
||||
|
||||
@@ -209,14 +209,14 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \DCarbone\UglyQueue::isLocked
|
||||
* @covers \DCarbone\isAlreadyLocked::isAlreadyLocked
|
||||
* @uses \DCarbone\UglyQueue
|
||||
* @depends testCanInitializeObjectWithValidParameters
|
||||
* @param \DCarbone\UglyQueue $uglyQueue
|
||||
*/
|
||||
public function testCanGetQueueLockedStatus(\DCarbone\UglyQueue $uglyQueue)
|
||||
{
|
||||
$locked = $uglyQueue->isLocked();
|
||||
$locked = $uglyQueue->isAlreadyLocked();
|
||||
$this->assertFalse($locked);
|
||||
}
|
||||
|
||||
@@ -239,7 +239,6 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testCanInitializeExistingQueue()
|
||||
{
|
||||
|
||||
$uglyQueue = new \DCarbone\UglyQueue($this->baseDir, 'tasty-sandwich');
|
||||
|
||||
$this->assertInstanceOf('\\DCarbone\\UglyQueue', $uglyQueue);
|
||||
@@ -256,7 +255,6 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testExceptionThrownWhenPassingNonIntegerValueToLock(\DCarbone\UglyQueue $uglyQueue)
|
||||
{
|
||||
|
||||
$uglyQueue->lock('7 billion');
|
||||
}
|
||||
|
||||
@@ -269,13 +267,12 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testExceptionThrownWhenPassingNegativeIntegerValueToLock(\DCarbone\UglyQueue $uglyQueue)
|
||||
{
|
||||
|
||||
$uglyQueue->lock(-73);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \DCarbone\UglyQueue::lock
|
||||
* @covers \DCarbone\UglyQueue::isLocked
|
||||
* @covers \DCarbone\isAlreadyLocked::isAlreadyLocked
|
||||
* @covers \DCarbone\UglyQueue::createLockFile
|
||||
* @uses \DCarbone\UglyQueue
|
||||
* @depends testCanInitializeObjectWithValidParameters
|
||||
@@ -284,7 +281,6 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testCanLockUglyQueueWithDefaultTTL(\DCarbone\UglyQueue $uglyQueue)
|
||||
{
|
||||
|
||||
$locked = $uglyQueue->lock();
|
||||
|
||||
$this->assertTrue($locked);
|
||||
@@ -303,7 +299,7 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
|
||||
/**
|
||||
* @covers \DCarbone\UglyQueue::lock
|
||||
* @covers \DCarbone\UglyQueue::isLocked
|
||||
* @covers \DCarbone\isAlreadyLocked::isAlreadyLocked
|
||||
* @uses \DCarbone\UglyQueue
|
||||
* @depends testCanInitializeExistingQueue
|
||||
* @param \DCarbone\UglyQueue $uglyQueue
|
||||
@@ -317,7 +313,7 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \DCarbone\UglyQueue::isLocked
|
||||
* @covers \DCarbone\isAlreadyLocked::isAlreadyLocked
|
||||
* @uses \DCarbone\UglyQueue
|
||||
* @depends testCanLockUglyQueueWithDefaultTTL
|
||||
* @param \DCarbone\UglyQueue $uglyQueue
|
||||
@@ -325,7 +321,7 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
public function testIsLockedReturnsTrueAfterLocking(\DCarbone\UglyQueue $uglyQueue)
|
||||
{
|
||||
|
||||
$isLocked = $uglyQueue->isLocked();
|
||||
$isLocked = $uglyQueue->isAlreadyLocked();
|
||||
$this->assertTrue($isLocked);
|
||||
}
|
||||
|
||||
@@ -348,7 +344,7 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \DCarbone\UglyQueue::isLocked
|
||||
* @covers \DCarbone\isAlreadyLocked::isAlreadyLocked
|
||||
* @uses \DCarbone\UglyQueue
|
||||
* @depends testCanUnlockLockedQueue
|
||||
* @param \DCarbone\UglyQueue $uglyQueue
|
||||
@@ -356,14 +352,14 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
public function testIsLockedReturnsFalseAfterUnlockingQueue(\DCarbone\UglyQueue $uglyQueue)
|
||||
{
|
||||
|
||||
$isLocked = $uglyQueue->isLocked();
|
||||
$isLocked = $uglyQueue->isAlreadyLocked();
|
||||
|
||||
$this->assertFalse($isLocked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \DCarbone\UglyQueue::lock
|
||||
* @covers \DCarbone\UglyQueue::isLocked
|
||||
* @covers \DCarbone\isAlreadyLocked::isAlreadyLocked
|
||||
* @uses \DCarbone\UglyQueue
|
||||
* @uses \DCarbone\Helpers\FileHelper
|
||||
* @depends testCanUnlockLockedQueue
|
||||
@@ -373,18 +369,18 @@ class UglyQueueTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
$uglyQueue->lock(2);
|
||||
$isLocked = $uglyQueue->isLocked();
|
||||
$isLocked = $uglyQueue->isAlreadyLocked();
|
||||
$this->assertTrue($isLocked);
|
||||
|
||||
sleep(3);
|
||||
|
||||
$isLocked = $uglyQueue->isLocked();
|
||||
$isLocked = $uglyQueue->isAlreadyLocked();
|
||||
$this->assertFalse($isLocked);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \DCarbone\UglyQueue::lock
|
||||
* @covers \DCarbone\UglyQueue::isLocked
|
||||
* @covers \DCarbone\isAlreadyLocked::isAlreadyLocked
|
||||
* @uses \DCarbone\UglyQueue
|
||||
* @depends testCanUnlockLockedQueue
|
||||
* @param \DCarbone\UglyQueue $uglyQueue
|
||||
|
||||
Reference in New Issue
Block a user