diff --git a/.gitignore b/.gitignore index 22d0d82..5556efb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ vendor +phpunit.xml diff --git a/src/Presque/AbstractJob.php b/src/Presque/AbstractJob.php index 21e8e53..ef8c2bc 100644 --- a/src/Presque/AbstractJob.php +++ b/src/Presque/AbstractJob.php @@ -27,28 +27,27 @@ public function getStatus() return $this->status; } + /** + * {@inheritDoc} + */ public function isSuccessful() { return StatusInterface::SUCCESS === $this->getStatus(); } + /** + * {@inheritDoc} + */ public function isError() { return StatusInterface::FAILED === $this->getStatus(); } + /** + * {@inheritDoc} + */ public function isActive() { return StatusInterface::RUNNING === $this->getStatus(); } - - public function isTrackable() - { - - } - - public function getMaxAttempts() - { - - } } \ No newline at end of file diff --git a/src/Presque/Event/JobEvent.php b/src/Presque/Event/JobEvent.php new file mode 100644 index 0000000..4774bf0 --- /dev/null +++ b/src/Presque/Event/JobEvent.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Presque\Event; + +use Presque\JobInterface; +use Presque\QueueInterface; +use Presque\WorkerInterface; + +class JobEvent extends Event +{ + private $worker; + private $canceled; + + public function __construct(JobInterface $job, QueueInterface $queue, WorkerInterface $worker) + { + $this->job = $job; + $this->queue = $queue; + $this->worker = $worker; + $this->canceled = false; + } + + public function getJob() + { + return $this->job; + } + + public function setJob(JobInterface $job) + { + $this->job = $job; + + return $this; + } + + public function getQueue() + { + return $this->queue; + } + + public function getWorker() + { + return $this->worker; + } + + public function cancel() + { + $this->canceled = true; + } + + public function isCanceled() + { + return $this->canceled; + } +} \ No newline at end of file diff --git a/src/Presque/Event/WorkerEvent.php b/src/Presque/Event/WorkerEvent.php index db4075f..0bcd220 100644 --- a/src/Presque/Event/WorkerEvent.php +++ b/src/Presque/Event/WorkerEvent.php @@ -11,12 +11,31 @@ namespace Presque\Event; +use Presque\WorkerInterface; + class WorkerEvent extends Event { private $worker; + private $canceled; public function __construct(WorkerInterface $worker) { $this->worker = $worker; + $this->canceled = false; + } + + public function getWorker() + { + return $this->worker; + } + + public function cancel() + { + $this->canceled = true; + } + + public function isCanceled() + { + return $this->canceled; } } \ No newline at end of file diff --git a/src/Presque/Events.php b/src/Presque/Events.php index fc465a6..9519251 100644 --- a/src/Presque/Events.php +++ b/src/Presque/Events.php @@ -18,4 +18,6 @@ final class Events const WORK_PAUSED = 'presque.work.paused'; const WORK_STOPPED = 'presque.work.stopped'; + + const JOB_STARTED = 'presque.job.started'; } \ No newline at end of file diff --git a/src/Presque/Job.php b/src/Presque/Job.php index 3654265..e61fa4f 100644 --- a/src/Presque/Job.php +++ b/src/Presque/Job.php @@ -25,11 +25,20 @@ class Job extends AbstractJob private $reflMethod; private $instance; + /** + * {@inheritDoc} + */ public static function create($class, array $args = array()) { return new static($class, $args); } + /** + * @param string $class Class that will be performing + * @param array $args List of arguments to pass to the `$class->perform()` method + * + * @throws InvalidArgumentException If `$class` does not implement the required methods + */ public function __construct($class, array $args = array()) { try { @@ -50,8 +59,15 @@ public function __construct($class, array $args = array()) $method = $refl->getMethod('perform'); if (!$method->isPublic()) { + $visibility = 'unknown'; + if ($method->isPrivate()) { + $visibility = 'private'; + } elseif ($method->isProtected()) { + $visibility = 'protected'; + } + throw new InvalidArgumentException( - 'The "perform" method for class "' . $class . '" must be public, not ' . $method->getVisiblity() + 'The "perform" method for class "' . $class . '" must be public, not ' . $visibility ); } @@ -69,6 +85,37 @@ public function __construct($class, array $args = array()) $this->reflMethod = $method; } + /** + * {@inheritDoc} + */ + public function getClass() + { + return $this->class; + } + + /** + * {@inheritDoc} + */ + public function getArguments() + { + return $this->args; + } + + /** + * {@inheritDoc} + */ + public function getInstance() + { + if (!$this->instance) { + $this->instance = $this->reflClass->newInstance(); + } + + return $this->instance; + } + + /** + * {@inheritDoc} + */ public function perform() { $this->lastResult = $this->lastError = null; @@ -89,28 +136,4 @@ public function perform() return $this; } - - public function getMaxAttempts() - { - - } - - public function getClass() - { - return $this->class; - } - - public function getArguments() - { - return $this->args; - } - - public function getInstance() - { - if (!$this->instance) { - $this->instance = $this->reflClass->newInstance(); - } - - return $this->instance; - } } \ No newline at end of file diff --git a/src/Presque/JobInterface.php b/src/Presque/JobInterface.php index d7f819a..82db349 100644 --- a/src/Presque/JobInterface.php +++ b/src/Presque/JobInterface.php @@ -13,17 +13,52 @@ interface JobInterface { + /** + * @param string $class Class that will be performing + * @param array $args List of arguments to pass to the `$class->perform()` method + * + * @throws InvalidArgumentException If `$class` does not implement the required methods + */ static function create($class, array $args = array()); + /** + * @return Boolean + */ function isSuccessful(); + /** + * @return Boolean + */ function isError(); + /** + * @return Boolean + */ function isActive(); + /** + * Does the work + */ function perform(); + /** + * Returns an instance of the `class` + * + * @return mixed + */ + function getInstance(); + + /** + * Returns the class name associated with this Job + * + * @return string + */ function getClass(); + /** + * Returns a list of arguments to pass to the `perform` method + * + * @return array + */ function getArguments(); } \ No newline at end of file diff --git a/src/Presque/Worker.php b/src/Presque/Worker.php index 276c6ee..e609416 100644 --- a/src/Presque/Worker.php +++ b/src/Presque/Worker.php @@ -12,12 +12,15 @@ namespace Presque; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Presque\Event\JobEvent; +use Presque\Event\WorkerEvent; class Worker implements WorkerInterface { private $id; private $queues; private $status; + private $eventDispatcher; public function __construct($id = null) { @@ -111,6 +114,14 @@ public function isDying() */ public function start() { + if ($this->hasEventDispatcher()) { + $event = $this->eventDispatcher(Events::WORK_STARTED, new WorkerEvent($this)); + + if ($event->isCanceled()) { + return; + } + } + $this->setStatus(StatusInterface::RUNNING); $this->run(); @@ -145,6 +156,16 @@ protected function process(QueueInterface $queue) return; } + if ($this->hasEventDispatcher()) { + $event = $this->eventDispatcher->dispatch(Events::JOB_STARTED, new JobEvent($job, $queue, $this)); + + if ($event->isCanceled()) { + return; + } + + $job = $event->getJob(); + } + $job->perform(); if ($job->isSuccessful()) { diff --git a/tests/Presque/Tests/JobTest.php b/tests/Presque/Tests/JobTest.php index 148fe31..82065df 100644 --- a/tests/Presque/Tests/JobTest.php +++ b/tests/Presque/Tests/JobTest.php @@ -39,6 +39,30 @@ public function testCreatingASimpleJobWithTooFewArguments() Job::create('Presque\Tests\Jobs\SimpleJob', array(1)); } + /** + * @expectedException Presque\Exception\InvalidArgumentException + */ + public function testCreatingAJobWithInvalidPerformMethod() + { + Job::create('Presque\Tests\Jobs\InvalidJob'); + } + + /** + * @expectedException Presque\Exception\InvalidArgumentException + */ + public function testCreatingAJobWithPrivatePerformMethod() + { + Job::create('Presque\Tests\Jobs\PrivateJob'); + } + + /** + * @expectedException Presque\Exception\InvalidArgumentException + */ + public function testCreatingAnIncompleteJob() + { + Job::create('Presque\Tests\Jobs\IncompleteJob'); + } + public function testCreatingASimpleJob() { $job = Job::create('Presque\Tests\Jobs\SimpleJob', array('simple', 'jobs')); diff --git a/tests/Presque/Tests/Jobs/IncompleteJob.php b/tests/Presque/Tests/Jobs/IncompleteJob.php new file mode 100644 index 0000000..180ce96 --- /dev/null +++ b/tests/Presque/Tests/Jobs/IncompleteJob.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Presque\Tests\Jobs; + +class IncompleteJob +{ +} \ No newline at end of file diff --git a/tests/Presque/Tests/Jobs/InvalidJob.php b/tests/Presque/Tests/Jobs/InvalidJob.php new file mode 100644 index 0000000..847a741 --- /dev/null +++ b/tests/Presque/Tests/Jobs/InvalidJob.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Presque\Tests\Jobs; + +class InvalidJob +{ + protected function perform() + { + throw new \RuntimeException('The InvalidJob should never be performed!'); + } +} \ No newline at end of file diff --git a/tests/Presque/Tests/Jobs/PrivateJob.php b/tests/Presque/Tests/Jobs/PrivateJob.php new file mode 100644 index 0000000..59faefb --- /dev/null +++ b/tests/Presque/Tests/Jobs/PrivateJob.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Presque\Tests\Jobs; + +class PrivateJob +{ + private function perform() + { + throw new \RuntimeException('The PrivateJob should never be performed!'); + } +} \ No newline at end of file diff --git a/tests/Presque/Tests/QueueTest.php b/tests/Presque/Tests/QueueTest.php index 553ce03..7365ffd 100644 --- a/tests/Presque/Tests/QueueTest.php +++ b/tests/Presque/Tests/QueueTest.php @@ -15,6 +15,16 @@ class QueueTest extends TestCase { + public function testCreatingQueueInstance() + { + $storage = $this->getStorageMock(); + + $queue = new Queue('queue', $storage); + + $this->assertEquals('queue', $queue->getName()); + $this->assertEquals($storage, $queue->getStorage()); + } + public function testAddingJobsToQueue() { $job = $this->getMock('Presque\JobInterface'); @@ -67,6 +77,20 @@ public function testGrabbingJobFromQueue() $this->assertEquals(array('simple', 'job'), $job->getArguments()); } + public function testAnEmptyQueue() + { + $storage = $this->getStorageMock(); + $storage + ->expects($this->once()) + ->method('pop') + ->with($this->equalTo('queuyou'), $this->equalTo(10)) + ->will($this->returnValue(null)); + + $queue = new Queue('queuyou', $storage); + + $this->assertFalse($queue->reserve()); + } + private function getStorageMock() { return $this->getMock('Presque\Storage\StorageInterface');