Legoktm has uploaded a new change for review. https://gerrit.wikimedia.org/r/297697
Change subject: Make LocalRename jobs run sequentially ...................................................................... Make LocalRename jobs run sequentially Running the job parallel on each wiki caused problems for users with many accounts due to DB errors when all jobs tried to change the central user record at the same time. Run one wiki after the other instead, with each job scheduling the next job when it is finished. Bug: T137973 Change-Id: I00f2710080897030a3e44a8c8490d991d703bb21 (cherry picked from commit 053b4ce1e137d7bbade69bcf2f8c6dcd17e0651f) --- M includes/GlobalRename/GlobalRenameUser.php M includes/GlobalRename/GlobalRenameUserStatus.php M includes/LocalRenameJob/LocalRenameJob.php 3 files changed, 59 insertions(+), 9 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/CentralAuth refs/changes/97/297697/1 diff --git a/includes/GlobalRename/GlobalRenameUser.php b/includes/GlobalRename/GlobalRenameUser.php index 59b69b8..f3a6c8d 100644 --- a/includes/GlobalRename/GlobalRenameUser.php +++ b/includes/GlobalRename/GlobalRenameUser.php @@ -173,9 +173,12 @@ */ private function injectLocalRenameUserJobs( array $wikis, array $options ) { $job = $this->getJob( $options ); - // Submit the jobs. - foreach( $wikis as $wiki ) { - call_user_func( $this->jobQueueGroupGenerator, $wiki )->push( $job ); + $statuses = $this->renameuserStatus->getStatuses( GlobalRenameUserStatus::READ_LATEST ); + foreach ( $statuses as $wiki => $status ) { + if ( $status === 'queued' ) { + call_user_func( $this->jobQueueGroupGenerator, $wiki )->push( $job ); + break; + } } } diff --git a/includes/GlobalRename/GlobalRenameUserStatus.php b/includes/GlobalRename/GlobalRenameUserStatus.php index 1d2bb6e..ecb6101 100644 --- a/includes/GlobalRename/GlobalRenameUserStatus.php +++ b/includes/GlobalRename/GlobalRenameUserStatus.php @@ -9,7 +9,7 @@ * @author Marius Hoch < h...@online.de > */ -class GlobalRenameUserStatus { +class GlobalRenameUserStatus implements IDBAccessObject { /** * Either old or new name of the user @@ -96,16 +96,20 @@ * Get a user's rename status for all wikis. * Returns an array ( wiki => status ) * + * @param integer $flags IDBAccessObject flags + * * @return array */ - public function getStatuses() { - $dbr = $this->getDB(); + public function getStatuses( $flags = 0 ) { + list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags ); + $db = $this->getDB( $index ); - $res = $dbr->select( + $res = $db->select( 'renameuser_status', array( 'ru_wiki', 'ru_status' ), - array( $this->getNameWhereClause( $dbr ) ), - __METHOD__ + array( $this->getNameWhereClause( $db ) ), + __METHOD__, + $options ); $statuses = array(); @@ -117,6 +121,19 @@ } /** + * Get a user's rename status for the current wiki. + * + * @param integer $flags IDBAccessObject flags + * + * @return string|null Null means no rename pending for this user on the current wiki (possibly + * because it has finished already). + */ + public function getStatus( $flags = 0 ) { + $statuses = $this->getStatuses( $flags ); + return isset( $statuses[wfWikiID()] ) ? $statuses[wfWikiID()] : null; + } + + /** * Set the rename status for a certain wiki * * @param string $wiki diff --git a/includes/LocalRenameJob/LocalRenameJob.php b/includes/LocalRenameJob/LocalRenameJob.php index c4285b6..d696338 100644 --- a/includes/LocalRenameJob/LocalRenameJob.php +++ b/includes/LocalRenameJob/LocalRenameJob.php @@ -1,5 +1,7 @@ <?php +use MediaWiki\Logger\LoggerFactory; + /** * Base class for jobs that change a user's * name. Intended to be run on local wikis @@ -13,6 +15,18 @@ public function run() { $this->setRenameUserStatus( new GlobalRenameUserStatus( $this->params['to'] ) ); + + // bail if it's already done or in progress + $status = $this->renameuserStatus->getStatus( GlobalRenameUserStatus::READ_LATEST ); + if ( $status !== 'queued' && $status !== 'failed' ) { + LoggerFactory::getInstance( 'rename' )->info( 'skipping duplicate rename from {user}', [ + 'user' => $this->params['from'], + 'to' => $this->params['to'], + 'status' => $status, + ] ); + return true; + } + if ( isset( $this->params['session'] ) ) { // Don't carry over users or sessions because it's going to be wrong // across wikis @@ -25,6 +39,7 @@ } try { $this->doRun(); + $this->scheduleNextWiki(); } catch ( Exception $e ) { // This will lock the user out of their account // until a sysadmin intervenes @@ -87,4 +102,19 @@ protected function updateStatus( $status ) { $this->renameuserStatus->setStatus( wfWikiID(), $status ); } + + protected function scheduleNextWiki() { + $job = new static( $this->getTitle(), $this->getParams() ); + $nextWiki = null; + $statuses = $this->renameuserStatus->getStatuses( GlobalRenameUserStatus::READ_LATEST ); + foreach ( $statuses as $wiki => $status ) { + if ( $status === 'queued' && $wiki !== wfWikiID() ) { + $nextWiki = $wiki; + break; + } + } + if ( $nextWiki ) { + JobQueueGroup::singleton( $nextWiki )->push( $job ); + } + } } -- To view, visit https://gerrit.wikimedia.org/r/297697 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I00f2710080897030a3e44a8c8490d991d703bb21 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/CentralAuth Gerrit-Branch: wmf/1.28.0-wmf.8 Gerrit-Owner: Legoktm <legoktm.wikipe...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits