From e049bcb87f157d9157c5f1f4034de57f8a4ba44c Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Mon, 27 Jan 2014 13:28:47 -0800 Subject: [PATCH] Added a simple JobSpecification class for pushing jobs * Both this and the full Job class can be used to push jobs bug: 60403 Change-Id: I7e78321b5919e48fd8228580ddde7c90a6e4024e --- includes/AutoLoader.php | 2 + includes/job/Job.php | 5 +- includes/job/JobQueueDB.php | 4 +- includes/job/JobQueueGroup.php | 2 +- includes/job/JobQueueRedis.php | 8 +- includes/job/JobSpecification.php | 189 ++++++++++++++++++++++++++++++ 6 files changed, 201 insertions(+), 9 deletions(-) create mode 100644 includes/job/JobSpecification.php diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index dabcc5c00e..fb43b25273 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -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', diff --git a/includes/job/Job.php b/includes/job/Job.php index 067ede1ad7..5fc1e0644c 100644 --- a/includes/job/Job.php +++ b/includes/job/Job.php @@ -1,6 +1,6 @@ getMasterDB(); return array( diff --git a/includes/job/JobQueueGroup.php b/includes/job/JobQueueGroup.php index d71df15d15..90742ced39 100644 --- a/includes/job/JobQueueGroup.php +++ b/includes/job/JobQueueGroup.php @@ -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." ); diff --git a/includes/job/JobQueueRedis.php b/includes/job/JobQueueRedis.php index 9b9fe2d4e2..212871e263 100644 --- a/includes/job/JobQueueRedis.php +++ b/includes/job/JobQueueRedis.php @@ -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 index 0000000000..5bfee0bc2a --- /dev/null +++ b/includes/job/JobSpecification.php @@ -0,0 +1,189 @@ + + * $job = new JobSpecification( + * 'null', + * array( 'lives' => 1, 'usleep' => 100, 'pi' => 3.141569 ), + * array( 'removeDuplicates' => 1 ), + * Title::makeTitle( NS_SPECIAL, 'nullity' ) + * ); + * JobQueueGroup::singleton()->push( $job ) + * + * + * @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; + } +} -- 2.20.1