'ThumbnailRender' => 'ThumbnailRenderJob',
'recentChangesUpdate' => 'RecentChangesUpdateJob',
'refreshLinksPrioritized' => 'RefreshLinksJob', // for cascading protection
+ 'refreshLinksDynamic' => 'RefreshLinksJob', // for pages with dynamic content
'activityUpdateJob' => 'ActivityUpdateJob',
'enqueue' => 'EnqueueJob', // local queue for multi-DC setups
'null' => 'NullJob'
// Which ever runs first generally no-ops the other one.
$jobs = array();
foreach ( $bc->getCascadeProtectedLinks() as $title ) {
- $jobs[] = new RefreshLinksJob( $title, array( 'prioritize' => true ) );
+ $jobs[] = RefreshLinksJob::newPrioritized( $title, array() );
}
JobQueueGroup::singleton()->push( $jobs );
}
'job' => new JobSpecification(
'refreshLinksPrioritized',
array(
- 'prioritize' => true,
// Reuse the parser cache if it was saved
'rootJobTimestamp' => $this->mParserOutput->getCacheTime(),
'useRecursiveLinksUpdate' => $this->mRecursive
*/
public static function factory( $command, Title $title, $params = array() ) {
global $wgJobClasses;
+
if ( isset( $wgJobClasses[$command] ) ) {
$class = $wgJobClasses[$command];
- return new $class( $title, $params );
+ $job = new $class( $title, $params );
+ $job->command = $command;
+
+ return $job;
}
- throw new MWException( "Invalid job command `{$command}`" );
+
+ throw new InvalidArgumentException( "Invalid job command '{$command}'" );
}
/**
function __construct( Title $title, array $params ) {
parent::__construct( 'refreshLinks', $title, $params );
- // A separate type is used just for cascade-protected backlinks
- if ( !empty( $this->params['prioritize'] ) ) {
- $this->command .= 'Prioritized';
- }
// Base backlink update jobs and per-title update jobs can be de-duplicated.
// If template A changes twice before any jobs run, a clean queue will have:
// (A base, A base)
&& ( !isset( $params['pages'] ) || count( $params['pages'] ) == 1 );
}
+ /**
+ * @param Title $title
+ * @param array $params
+ * @return RefreshLinksJob
+ */
+ public static function newPrioritized( Title $title, array $params ) {
+ $job = new self( $title, $params );
+ $job->command = 'refreshLinksPrioritized';
+
+ return $job;
+ }
+
+ /**
+ * @param Title $title
+ * @param array $params
+ * @return RefreshLinksJob
+ */
+ public static function newDynamic( Title $title, array $params ) {
+ $job = new self( $title, $params );
+ $job->command = 'refreshLinksDynamic';
+
+ return $job;
+ }
+
function run() {
global $wgUpdateRowsPerJob;
return;
}
+ $params = array(
+ 'isOpportunistic' => true,
+ 'rootJobTimestamp' => $parserOutput->getCacheTime()
+ );
+
if ( $this->mTitle->areRestrictionsCascading() ) {
// If the page is cascade protecting, the links should really be up-to-date
- $params = array( 'prioritize' => true );
+ JobQueueGroup::singleton()->lazyPush(
+ RefreshLinksJob::newPrioritized( $this->mTitle, $params )
+ );
} elseif ( $parserOutput->hasDynamicContent() ) {
- // Assume the output contains time/random based magic words
- $params = array();
- } else {
- // If the inclusions are deterministic, the edit-triggered link jobs are enough
- return;
- }
-
- // Check if the last link refresh was before page_touched
- if ( $this->getLinksTimestamp() < $this->getTouched() ) {
- $params['isOpportunistic'] = true;
- $params['rootJobTimestamp'] = $parserOutput->getCacheTime();
- JobQueueGroup::singleton()->lazyPush( new RefreshLinksJob( $this->mTitle, $params ) );
+ // Assume the output contains "dynamic" time/random based magic words.
+ // Only update pages that expired due to dynamic content and NOT due to edits
+ // to referenced templates/files. When the cache expires due to dynamic content,
+ // page_touched is unchanged. We want to avoid triggering redundant jobs due to
+ // views of pages that were just purged via HTMLCacheUpdateJob. In that case, the
+ // template/file edit already triggered recursive RefreshLinksJob jobs.
+ if ( $this->getLinksTimestamp() > $this->getTouched() ) {
+ // If a page is uncacheable, do not keep spamming a job for it.
+ // Although it would be de-duplicated, it would still waste I/O.
+ $cache = ObjectCache::getLocalClusterInstance();
+ $key = $cache->makeKey( 'dynamic-linksupdate', 'last', $this->getId() );
+ if ( $cache->add( $key, time(), 60 ) ) {
+ JobQueueGroup::singleton()->lazyPush(
+ RefreshLinksJob::newDynamic( $this->mTitle, $params )
+ );
+ }
+ }
}
}