Added a simple JobSpecification class for pushing jobs
authorAaron Schulz <aschulz@wikimedia.org>
Mon, 27 Jan 2014 21:28:47 +0000 (13:28 -0800)
committerAaron Schulz <aschulz@wikimedia.org>
Tue, 28 Jan 2014 18:35:48 +0000 (10:35 -0800)
* Both this and the full Job class can be used to push jobs

bug: 60403
Change-Id: I7e78321b5919e48fd8228580ddde7c90a6e4024e

includes/AutoLoader.php
includes/job/Job.php
includes/job/JobQueueDB.php
includes/job/JobQueueGroup.php
includes/job/JobQueueRedis.php
includes/job/JobSpecification.php [new file with mode: 0644]

index dabcc5c..fb43b25 100644 (file)
@@ -636,6 +636,7 @@ $wgAutoloadLocalClasses = array(
        'WebInstallerPage' => 'includes/installer/WebInstallerPage.php',
 
        # includes/job
+       'IJobSpecification' => 'includes/job/JobSpecification.php',
        'Job' => 'includes/job/Job.php',
        'JobQueue' => 'includes/job/JobQueue.php',
        'JobQueueAggregator' => 'includes/job/aggregator/JobQueueAggregator.php',
@@ -647,6 +648,7 @@ $wgAutoloadLocalClasses = array(
        'JobQueueGroup' => 'includes/job/JobQueueGroup.php',
        'JobQueueFederated' => 'includes/job/JobQueueFederated.php',
        'JobQueueRedis' => 'includes/job/JobQueueRedis.php',
+       'JobSpecification' => 'includes/job/JobSpecification.php',
 
        # includes/job/jobs
        'DoubleRedirectJob' => 'includes/job/jobs/DoubleRedirectJob.php',
index 067ede1..5fc1e06 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 /**
- * Job queue base code.
+ * Job queue task base code.
  *
  * 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
 /**
  * Class to both describe a background job and handle jobs.
  * The queue aspects of this class are now deprecated.
+ * Using the class to push jobs onto queues is deprecated (use JobSpecification).
  *
  * @ingroup JobQueue
  */
-abstract class Job {
+abstract class Job implements IJobSpecification {
        /** @var string */
        public $command;
 
index e7a269a..6097d31 100644 (file)
@@ -723,10 +723,10 @@ class JobQueueDB extends JobQueue {
        }
 
        /**
-        * @param Job $job
+        * @param IJobSpecification $job
         * @return array
         */
-       protected function insertFields( Job $job ) {
+       protected function insertFields( IJobSpecification $job ) {
                $dbw = $this->getMasterDB();
 
                return array(
index d71df15..90742ce 100644 (file)
@@ -116,7 +116,7 @@ class JobQueueGroup {
 
                $jobsByType = array(); // (job type => list of jobs)
                foreach ( $jobs as $job ) {
-                       if ( $job instanceof Job ) {
+                       if ( $job instanceof IJobSpecification ) {
                                $jobsByType[$job->getType()][] = $job;
                        } else {
                                throw new MWException( "Attempted to push a non-Job object into a queue." );
index 9b9fe2d..212871e 100644 (file)
@@ -765,10 +765,10 @@ LUA;
        }
 
        /**
-        * @param Job $job
+        * @param IJobSpecification $job
         * @return array
         */
-       protected function getNewJobFields( Job $job ) {
+       protected function getNewJobFields( IJobSpecification $job ) {
                return array(
                        // Fields that describe the nature of the job
                        'type' => $job->getType(),
@@ -780,8 +780,8 @@ LUA;
                        // Additional job metadata
                        'uuid' => UIDGenerator::newRawUUIDv4( UIDGenerator::QUICK_RAND ),
                        'sha1' => $job->ignoreDuplicates()
-                                       ? wfBaseConvert( sha1( serialize( $job->getDeduplicationInfo() ) ), 16, 36, 31 )
-                                       : '',
+                               ? wfBaseConvert( sha1( serialize( $job->getDeduplicationInfo() ) ), 16, 36, 31 )
+                               : '',
                        'timestamp' => time() // UNIX timestamp
                );
        }
diff --git a/includes/job/JobSpecification.php b/includes/job/JobSpecification.php
new file mode 100644 (file)
index 0000000..5bfee0b
--- /dev/null
@@ -0,0 +1,189 @@
+<?php
+/**
+ * Job queue task description base code.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup JobQueue
+ */
+
+/**
+ * Job queue task description interface
+ *
+ * @ingroup JobQueue
+ * @since 1.23
+ */
+interface IJobSpecification {
+       /**
+        * @return string Job type
+        */
+       public function getType();
+
+       /**
+        * @return array
+        */
+       public function getParams();
+
+       /**
+        * @return int|null UNIX timestamp to delay running this job until, otherwise null
+        */
+       public function getReleaseTimestamp();
+
+       /**
+        * @return bool Whether only one of each identical set of jobs should be run
+        */
+       public function ignoreDuplicates();
+
+       /**
+        * Subclasses may need to override this to make duplication detection work.
+        * The resulting map conveys everything that makes the job unique. This is
+        * only checked if ignoreDuplicates() returns true, meaning that duplicate
+        * jobs are supposed to be ignored.
+        *
+        * @return array Map of key/values
+        */
+       public function getDeduplicationInfo();
+
+       /**
+        * @return Title Descriptive title (this can simply be informative)
+        */
+       public function getTitle();
+}
+
+/**
+ * Job queue task description base code
+ *
+ * Example usage:
+ * <code>
+ * $job = new JobSpecification(
+ *             'null',
+ *             array( 'lives' => 1, 'usleep' => 100, 'pi' => 3.141569 ),
+ *             array( 'removeDuplicates' => 1 ),
+ *             Title::makeTitle( NS_SPECIAL, 'nullity' )
+ * );
+ * JobQueueGroup::singleton()->push( $job )
+ * </code>
+ *
+ * @ingroup JobQueue
+ * @since 1.23
+ */
+class JobSpecification implements IJobSpecification {
+       /** @var string */
+       protected $type;
+
+       /** @var array Array of job parameters or false if none */
+       protected $params;
+
+       /** @var Title */
+       protected $title;
+
+       /** @var bool Expensive jobs may set this to true */
+       protected $removeDuplicates;
+
+       /**
+        * @param string $type
+        * @param array $params Map of key/values
+        * @param array $opts Map of key/values
+        * @param Title $title Optional descriptive title
+        */
+       public function __construct(
+               $type, array $params, array $opts = array(), Title $title = null
+       ) {
+               $this->validateParams( $params );
+
+               $this->type = $type;
+               $this->params = $params;
+               $this->title = $title ?: Title::newMainPage();
+               $this->removeDuplicates = !empty( $opts['removeDuplicates'] );
+       }
+
+       /**
+        * @param array $params
+        */
+       protected function validateParams( array $params ) {
+               foreach ( $params as $p => $v ) {
+                       if ( is_array( $v ) ) {
+                               $this->validateParams( $v );
+                       } elseif ( !is_scalar( $v ) && $v !== null ) {
+                               throw new UnexpectedValueException( 'Job parameters are not JSON serializable.' );
+                       }
+               }
+       }
+
+       /**
+        * @return string
+        */
+       public function getType() {
+               return $this->type;
+       }
+
+       /**
+        * @return Title
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * @return array
+        */
+       public function getParams() {
+               return $this->params;
+       }
+
+       /**
+        * @return int|null UNIX timestamp to delay running this job until, otherwise null
+        */
+       public function getReleaseTimestamp() {
+               return isset( $this->params['jobReleaseTimestamp'] )
+                       ? wfTimestampOrNull( TS_UNIX, $this->params['jobReleaseTimestamp'] )
+                       : null;
+       }
+
+       /**
+        * @return bool Whether only one of each identical set of jobs should be run
+        */
+       public function ignoreDuplicates() {
+               return $this->removeDuplicates;
+       }
+
+       /**
+        * Subclasses may need to override this to make duplication detection work.
+        * The resulting map conveys everything that makes the job unique. This is
+        * only checked if ignoreDuplicates() returns true, meaning that duplicate
+        * jobs are supposed to be ignored.
+        *
+        * @return array Map of key/values
+        */
+       public function getDeduplicationInfo() {
+               $info = array(
+                       'type' => $this->getType(),
+                       'namespace' => $this->getTitle()->getNamespace(),
+                       'title' => $this->getTitle()->getDBkey(),
+                       'params' => $this->getParams()
+               );
+               if ( is_array( $info['params'] ) ) {
+                       // Identical jobs with different "root" jobs should count as duplicates
+                       unset( $info['params']['rootJobSignature'] );
+                       unset( $info['params']['rootJobTimestamp'] );
+                       // Likewise for jobs with different delay times
+                       unset( $info['params']['jobReleaseTimestamp'] );
+               }
+
+               return $info;
+       }
+}