26use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
43 const NORMAL_MAX_LAG = 10;
45 const LAG_WAIT_TIMEOUT = 15;
50 $this->removeDuplicates = (
56 $this->params += [
'causeAction' =>
'unknown',
'causeAgent' =>
'unknown' ];
60 $this->executionFlags |= self::JOB_NO_EXPLICIT_TRX_ROUND;
70 $job->command =
'refreshLinksPrioritized';
82 $job->command =
'refreshLinksDynamic';
91 if ( !empty( $this->params[
'recursive'] ) ) {
92 $services = MediaWikiServices::getInstance();
96 if ( !isset( $this->params[
'range'] ) ) {
97 $lbFactory = $services->getDBLoadBalancerFactory();
98 if ( !$lbFactory->waitForReplication( [
99 'domain' => $lbFactory->getLocalDomainID(),
100 'timeout' => self::LAG_WAIT_TIMEOUT
102 $stats = $services->getStatsdDataFactory();
103 $stats->increment(
'refreshlinks.lag_wait_failed' );
108 $extraParams[
'triggeredRecursive'] =
true;
110 $extraParams[
'causeAction'] = $this->params[
'causeAction'];
111 $extraParams[
'causeAgent'] = $this->params[
'causeAgent'];
116 $services->getMainConfig()->get(
'UpdateRowsPerJob' ),
118 [
'params' => $extraParams ]
120 JobQueueGroup::singleton()->push( $jobs );
122 } elseif ( isset( $this->params[
'pages'] ) ) {
123 foreach ( $this->params[
'pages'] as list( $ns, $dbKey ) ) {
124 $title = Title::makeTitleSafe( $ns, $dbKey );
145 $services = MediaWikiServices::getInstance();
146 $stats = $services->getStatsdDataFactory();
147 $renderer = $services->getRevisionRenderer();
148 $parserCache = $services->getParserCache();
149 $lbFactory = $services->getDBLoadBalancerFactory();
150 $ticket = $lbFactory->getEmptyTransactionTicket( __METHOD__ );
153 $page = WikiPage::factory(
$title );
154 $page->loadPageData( WikiPage::READ_LATEST );
160 $dbw = $lbFactory->getMainLB()->getConnectionRef(
DB_MASTER );
162 $scopedLock = LinksUpdate::acquirePageLock( $dbw, $page->getId(),
'job' );
163 if ( $scopedLock ===
null ) {
165 $this->
setLastError(
'LinksUpdate already running for this page, try again later.' );
166 $stats->increment(
'refreshlinks.lock_failure' );
172 $stats->increment(
'refreshlinks.update_skipped' );
178 $lbFactory->beginMasterChanges( __METHOD__ );
179 $output = $this->
getParserOutput( $renderer, $parserCache, $page, $stats );
181 $lbFactory->commitMasterChanges( __METHOD__ );
188 $options[
'known-revision-output'] = $output;
190 $page->doSecondaryDataUpdates( $options );
195 $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
206 $rootTimestamp = $this->params[
'rootJobTimestamp'] ??
null;
207 if ( $rootTimestamp ===
null ) {
211 if ( !empty( $this->params[
'isOpportunistic'] ) ) {
214 $lagAwareTimestamp = $rootTimestamp;
219 wfTimestamp( TS_UNIX, $rootTimestamp ) + self::NORMAL_MAX_LAG
239 StatsdDataFactoryInterface $stats
247 if ( $cachedOutput ) {
248 return $cachedOutput;
255 [
'audience' => $revision::RAW ]
259 $output = $renderedRevision->getRevisionParserOutput( [
'generate-html' =>
false ] );
260 $output->setCacheTime( $parseTimestamp );
274 StatsdDataFactoryInterface $stats
282 $triggeringRevisionId = $this->params[
'triggeringRevisionId'] ??
null;
283 if ( $triggeringRevisionId && $triggeringRevisionId !== $latest ) {
285 $stats->increment(
'refreshlinks.rev_not_current' );
286 $this->
setLastError(
"Revision $triggeringRevisionId is not current" );
295 $stats->increment(
'refreshlinks.rev_not_found' );
296 $this->
setLastError(
"Revision not found for {$title->getPrefixedDBkey()}" );
299 } elseif ( $revision->getId() !== $latest || $revision->getPageId() !== $page->
getId() ) {
304 $stats->increment(
'refreshlinks.rev_not_current' );
305 $this->
setLastError(
"Revision {$revision->getId()} is not current" );
326 StatsdDataFactoryInterface $stats
328 $cachedOutput =
null;
332 $rootTimestamp = $this->params[
'rootJobTimestamp'] ??
null;
333 if ( $rootTimestamp !==
null ) {
334 $opportunistic = !empty( $this->params[
'isOpportunistic'] );
335 if ( $opportunistic ) {
338 $lagAwareTimestamp = $rootTimestamp;
343 wfTimestamp( TS_UNIX, $rootTimestamp ) + self::NORMAL_MAX_LAG
347 if ( $page->
getTouched() >= $rootTimestamp || $opportunistic ) {
352 $output = $parserCache->
getDirty( $page, $parserOptions );
355 $output->getCacheRevisionId() == $currentRevision->
getId() &&
356 $output->getCacheTime() >= $lagAwareTimestamp
358 $cachedOutput = $output;
363 if ( $cachedOutput ) {
364 $stats->increment(
'refreshlinks.parser_cached' );
366 $stats->increment(
'refreshlinks.parser_uncached' );
369 return $cachedOutput;
377 'recursive' => !empty( $this->params[
'useRecursiveLinksUpdate'] ),
379 'causeAction' => $this->params[
'causeAction'],
380 'causeAgent' => $this->params[
'causeAgent']
382 if ( !empty( $this->params[
'triggeringUser'] ) ) {
383 $userInfo = $this->params[
'triggeringUser'];
384 if ( $userInfo[
'userId'] ) {
396 $info = parent::getDeduplicationInfo();
397 unset( $info[
'causeAction'] );
398 unset( $info[
'causeAgent'] );
399 if ( is_array( $info[
'params'] ) ) {
402 if ( isset( $info[
'params'][
'pages'] ) ) {
403 unset( $info[
'namespace'] );
404 unset( $info[
'title'] );
412 if ( !empty( $this->params[
'recursive'] ) ) {
414 } elseif ( isset( $this->params[
'pages'] ) ) {
415 return count( $this->params[
'pages'] );
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
static partitionBacklinkJob(Job $job, $bSize, $cSize, $opts=[])
Break down $job into approximately ($bSize/$cSize) leaf jobs and a single partition job that covers t...
static invalidateCache(Title $title, $revid=null)
Clear the info cache for a given Title.
Class to both describe a background job and handle jobs.
array $params
Array of job parameters.
getDirty( $article, $popts)
Retrieve the ParserOutput from ParserCache, even if it's outdated.
Job to update link tables for pages.
getDeduplicationInfo()
Subclasses may need to override this to make duplication detection work.
getParserOutput(RevisionRenderer $renderer, ParserCache $parserCache, WikiPage $page, StatsdDataFactoryInterface $stats)
Get the parser output if the page is unchanged from what was loaded in $page.
static newPrioritized(Title $title, array $params)
static newDynamic(Title $title, array $params)
getCurrentRevisionIfUnchanged(WikiPage $page, StatsdDataFactoryInterface $stats)
Get the current revision record if it is unchanged from what was loaded in $page.
isAlreadyRefreshed(WikiPage $page)
runForTitle(Title $title)
__construct(Title $title, array $params)
getParserOutputFromCache(ParserCache $parserCache, WikiPage $page, RevisionRecord $currentRevision, StatsdDataFactoryInterface $stats)
Get the parser output from cache if it reflects the change that triggered this job.
Represents a title within MediaWiki.
getLatestRevID( $flags=0)
What is the page_latest field for this page?
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
static newFromId( $id)
Static factory method for creation from a given user ID.
Class representing a MediaWiki article and history.
getLinksTimestamp()
Get the page_links_updated field.
makeParserOptions( $context)
Get parser options suitable for rendering the primary article wikitext.
getTitle()
Get the title object of the article.
getRevisionRecord()
Get the latest revision.
getTouched()
Get the page_touched field.
if(count( $args)< 1) $job