* @ingroup JobQueue
*/
use MediaWiki\MediaWikiServices;
-use Wikimedia\Rdbms\DBReplicationWaitError;
/**
* Job to update link tables for pages
// From then on, we know that any template changes at the time the base job was
// enqueued will be reflected in backlink page parses when the leaf jobs run.
if ( !isset( $this->params['range'] ) ) {
- try {
- $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
- $lbFactory->waitForReplication( [
+ $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+ if ( !$lbFactory->waitForReplication( [
'wiki' => wfWikiID(),
'timeout' => self::LAG_WAIT_TIMEOUT
- ] );
- } catch ( DBReplicationWaitError $e ) { // only try so hard
+ ] ) ) { // only try so hard
$stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
$stats->increment( 'refreshlinks.lag_wait_failed' );
}
$dbw = $lbFactory->getMainLB()->getConnection( DB_MASTER );
/** @noinspection PhpUnusedLocalVariableInspection */
$scopedLock = LinksUpdate::acquirePageLock( $dbw, $page->getId(), 'job' );
+ if ( $scopedLock === null ) {
+ // Another job is already updating the page, likely for an older revision (T170596).
+ $this->setLastError( 'LinksUpdate already running for this page, try again later.' );
+ return false;
+ }
// Get the latest ID *after* acquirePageLock() flushed the transaction.
// This is used to detect edits/moves after loadPageData() but before the scope lock.
// The works around the chicken/egg problem of determining the scope lock key.
$stats->increment( 'refreshlinks.parser_uncached' );
}
- $updates = $content->getSecondaryDataUpdates(
- $title,
- null,
- !empty( $this->params['useRecursiveLinksUpdate'] ),
- $parserOutput
- );
-
- // For legacy hook handlers doing updates via LinksUpdateConstructed, make sure
- // any pending writes they made get flushed before the doUpdate() calls below.
- // This avoids snapshot-clearing errors in LinksUpdate::acquirePageLock().
- $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
-
- foreach ( $updates as $update ) {
- // Carry over cause in case so the update can do extra logging
- $update->setCause( $this->params['causeAction'], $this->params['causeAgent'] );
- // FIXME: This code probably shouldn't be here?
- // Needed by things like Echo notifications which need
- // to know which user caused the links update
- if ( $update instanceof LinksUpdate ) {
- $update->setRevision( $revision );
- if ( !empty( $this->params['triggeringUser'] ) ) {
- $userInfo = $this->params['triggeringUser'];
- if ( $userInfo['userId'] ) {
- $user = User::newFromId( $userInfo['userId'] );
- } else {
- // Anonymous, use the username
- $user = User::newFromName( $userInfo['userName'], false );
- }
- $update->setTriggeringUser( $user );
- }
+ $options = [
+ 'recursive' => !empty( $this->params['useRecursiveLinksUpdate'] ),
+ // Carry over cause so the update can do extra logging
+ 'causeAction' => $this->params['causeAction'],
+ 'causeAgent' => $this->params['causeAgent'],
+ 'defer' => false,
+ 'transactionTicket' => $ticket,
+ ];
+ if ( !empty( $this->params['triggeringUser'] ) ) {
+ $userInfo = $this->params['triggeringUser'];
+ if ( $userInfo['userId'] ) {
+ $options['triggeringUser'] = User::newFromId( $userInfo['userId'] );
+ } else {
+ // Anonymous, use the username
+ $options['triggeringUser'] = User::newFromName( $userInfo['userName'], false );
}
}
-
- foreach ( $updates as $update ) {
- $update->setTransactionTicket( $ticket );
- $update->doUpdate();
- }
+ $page->doSecondaryDataUpdates( $options );
InfoAction::invalidateCache( $title );