Page MenuHomePhabricator

Selenium failures due to "Error 1213 from MediaWiki\Deferred\UserEditCountUpdate::doUpdate, Deadlock found when trying to get lock; try restarting transaction"
Closed, ResolvedPublic

Description

E.g. https://integration.wikimedia.org/ci/job/quibble-with-gated-extensions-selenium-php81/1204/console

12:40:01 mw-dberror.log:Mon Sep 22 10:30:43 UTC 2025	5a4886bf0b8e	wikidb	Error 1213 from MediaWiki\Deferred\UserEditCountUpdate::doUpdate, Deadlock found when trying to get lock; try restarting transaction UPDATE  `user` SET user_editcount = user_editcount+1 WHERE user_id = 32 AND (user_editcount IS NOT NULL) localhost:/workspace/db/quibble-mysql-y_ffhlj3/socket
12:40:01 mw-dberror.log:#0 /workspace/src/includes/libs/rdbms/database/Database.php(1197): Wikimedia\Rdbms\Database->getQueryExceptionAndLog(string, int, string, string)
12:40:01 mw-dberror.log:#1 /workspace/src/includes/libs/rdbms/database/Database.php(654): Wikimedia\Rdbms\Database->reportQueryError(string, int, string, string, bool)
12:40:01 mw-dberror.log:#2 /workspace/src/includes/libs/rdbms/database/Database.php(1537): Wikimedia\Rdbms\Database->query(Wikimedia\Rdbms\Query, string)
12:40:01 mw-dberror.log:#3 /workspace/src/includes/libs/rdbms/database/DBConnRef.php(127): Wikimedia\Rdbms\Database->update(string, array, array, string, array)
12:40:01 mw-dberror.log:#4 /workspace/src/includes/libs/rdbms/database/DBConnRef.php(457): Wikimedia\Rdbms\DBConnRef->__call(string, array)
12:40:01 mw-dberror.log:#5 /workspace/src/includes/libs/rdbms/querybuilder/UpdateQueryBuilder.php(332): Wikimedia\Rdbms\DBConnRef->update(string, array, array, string, array)
12:40:01 mw-dberror.log:#6 /workspace/src/includes/deferred/UserEditCountUpdate.php(90): Wikimedia\Rdbms\UpdateQueryBuilder->execute()
12:40:01 mw-dberror.log:#7 /workspace/src/includes/deferred/AutoCommitUpdate.php(47): MediaWiki\Deferred\UserEditCountUpdate->MediaWiki\Deferred\{closure}(Wikimedia\Rdbms\DBConnRef, string)
12:40:01 mw-dberror.log:#8 /workspace/src/includes/deferred/UserEditCountUpdate.php(107): MediaWiki\Deferred\AutoCommitUpdate->doUpdate()
12:40:01 mw-dberror.log:#9 /workspace/src/includes/deferred/DeferredUpdates.php(459): MediaWiki\Deferred\UserEditCountUpdate->doUpdate()
12:40:01 mw-dberror.log:#10 /workspace/src/includes/deferred/DeferredUpdates.php(201): MediaWiki\Deferred\DeferredUpdates::attemptUpdate(MediaWiki\Deferred\UserEditCountUpdate)
12:40:01 mw-dberror.log:#11 /workspace/src/includes/deferred/DeferredUpdates.php(288): MediaWiki\Deferred\DeferredUpdates::run(MediaWiki\Deferred\UserEditCountUpdate)
12:40:01 mw-dberror.log:#12 /workspace/src/includes/deferred/DeferredUpdatesScope.php(243): MediaWiki\Deferred\DeferredUpdates::MediaWiki\Deferred\{closure}(MediaWiki\Deferred\UserEditCountUpdate, int)
12:40:01 mw-dberror.log:#13 /workspace/src/includes/deferred/DeferredUpdatesScope.php(172): MediaWiki\Deferred\DeferredUpdatesScope->processStageQueue(int, int, Closure)
12:40:01 mw-dberror.log:#14 /workspace/src/includes/deferred/DeferredUpdates.php(307): MediaWiki\Deferred\DeferredUpdatesScope->processUpdates(int, Closure)
12:40:01 mw-dberror.log:#15 /workspace/src/includes/MediaWikiEntryPoint.php(302): MediaWiki\Deferred\DeferredUpdates::doUpdates(int)
12:40:01 mw-dberror.log:#16 /workspace/src/includes/MediaWikiEntryPoint.php(187): MediaWiki\MediaWikiEntryPoint->commitMainTransaction()
12:40:01 mw-dberror.log:#17 /workspace/src/includes/actions/ActionEntryPoint.php(206): MediaWiki\MediaWikiEntryPoint->doPrepareForOutput()
12:40:01 mw-dberror.log:#18 /workspace/src/includes/MediaWikiEntryPoint.php(170): MediaWiki\Actions\ActionEntryPoint->doPrepareForOutput()
12:40:01 mw-dberror.log:#19 /workspace/src/includes/actions/ActionEntryPoint.php(153): MediaWiki\MediaWikiEntryPoint->prepareForOutput()
12:40:01 mw-dberror.log:#20 /workspace/src/includes/MediaWikiEntryPoint.php(198): MediaWiki\Actions\ActionEntryPoint->execute()
12:40:01 mw-dberror.log:#21 /workspace/src/index.php(58): MediaWiki\MediaWikiEntryPoint->run()
12:40:01 mw-dberror.log:#22 {main}

This is a side effect of rMW3a52a5fe87af: User: Reduce locking severity of ::getInstanceForUpdate().

Event Timeline

UserEditCountUpdate doesn't seem to use (or need) any kind of locking. The relevant part of the code is

$dbw->newUpdateQueryBuilder()
	->update( 'user' )
	->set( [
		'user_editcount' => new RawSQLValue(
			'user_editcount+' . (int)$info->getIncrement()
		)
	] )
	->where( [ 'user_id' => $userId, $dbw->expr( 'user_editcount', '!=', null ) ] )
	->caller( $fname )->execute();

so I'm not super sure how the deadlock is happening here, or how exactly rMW3a52a5fe87af: User: Reduce locking severity of ::getInstanceForUpdate() has caused it.

The error is not from Selenium itself failing, but a check asserting that the error log is empty at the end of the Selenium test suite. But the exception URL is always /index.php?title=Special:EnrollAsMentor. GrowthExperiments uses User::getInstanceForUpdate() liberally, but none of the calls seem relevant here.

Another stack trace I'm seeing is

14:55:18 mw-dberror.log:Mon Sep 22 12:51:36 UTC 2025	aa4af6090d42	wikidb	Error 1213 from MediaWiki\User\User::loadFromDatabase, Deadlock found when trying to get lock; try restarting transaction SELECT  user_id,user_name,user_real_name,user_email,user_touched,user_token,user_email_authenticated,user_email_token,user_email_token_expires,user_registration,user_editcount,user_actor.actor_id  FROM `user` JOIN `actor` `user_actor` ON ((user_actor.actor_user = user_id))   WHERE user_id = 25  LIMIT 1   FOR UPDATE localhost:/workspace/db/quibble-mysql-hau_b2xp/socket
14:55:18 mw-dberror.log:#0 /workspace/src/includes/libs/rdbms/database/Database.php(1197): Wikimedia\Rdbms\Database->getQueryExceptionAndLog(string, int, string, string)
14:55:18 mw-dberror.log:#1 /workspace/src/includes/libs/rdbms/database/Database.php(654): Wikimedia\Rdbms\Database->reportQueryError(string, int, string, string, bool)
14:55:18 mw-dberror.log:#2 /workspace/src/includes/libs/rdbms/database/Database.php(1377): Wikimedia\Rdbms\Database->query(Wikimedia\Rdbms\Query, string)
14:55:18 mw-dberror.log:#3 /workspace/src/includes/libs/rdbms/database/Database.php(1387): Wikimedia\Rdbms\Database->select(array, array, array, string, array, array)
14:55:18 mw-dberror.log:#4 /workspace/src/includes/libs/rdbms/database/DBConnRef.php(127): Wikimedia\Rdbms\Database->selectRow(array, array, array, string, array, array)
14:55:18 mw-dberror.log:#5 /workspace/src/includes/libs/rdbms/database/DBConnRef.php(405): Wikimedia\Rdbms\DBConnRef->__call(string, array)
14:55:18 mw-dberror.log:#6 /workspace/src/includes/libs/rdbms/querybuilder/SelectQueryBuilder.php(810): Wikimedia\Rdbms\DBConnRef->selectRow(array, array, array, string, array, array)
14:55:18 mw-dberror.log:#7 /workspace/src/includes/user/User.php(1128): Wikimedia\Rdbms\SelectQueryBuilder->fetchRow()
14:55:18 mw-dberror.log:#8 /workspace/src/includes/user/User.php(489): MediaWiki\User\User->loadFromDatabase(int)
14:55:18 mw-dberror.log:#9 /workspace/src/includes/user/User.php(423): MediaWiki\User\User->loadFromId(int)
14:55:18 mw-dberror.log:#10 /workspace/src/includes/user/Options/UserOptionsUpdateJob.php(50): MediaWiki\User\User->load(int)
14:55:18 mw-dberror.log:#11 /workspace/src/includes/jobqueue/JobRunner.php(381): UserOptionsUpdateJob->run()
14:55:18 mw-dberror.log:#12 /workspace/src/includes/jobqueue/JobRunner.php(339): MediaWiki\JobQueue\JobRunner->doExecuteJob(UserOptionsUpdateJob)
14:55:18 mw-dberror.log:#13 /workspace/src/includes/jobqueue/JobRunner.php(234): MediaWiki\JobQueue\JobRunner->executeJob(UserOptionsUpdateJob)
14:55:18 mw-dberror.log:#14 /workspace/src/includes/MediaWikiEntryPoint.php(729): MediaWiki\JobQueue\JobRunner->run(array)
14:55:18 mw-dberror.log:#15 /workspace/src/includes/MediaWikiEntryPoint.php(268): MediaWiki\MediaWikiEntryPoint->triggerSyncJobs(int)
14:55:18 mw-dberror.log:#16 /workspace/src/includes/deferred/TransactionRoundDefiningUpdate.php(30): MediaWiki\MediaWikiEntryPoint->MediaWiki\{closure}()
14:55:18 mw-dberror.log:#17 /workspace/src/includes/deferred/DeferredUpdates.php(459): MediaWiki\Deferred\TransactionRoundDefiningUpdate->doUpdate()
14:55:18 mw-dberror.log:#18 /workspace/src/includes/deferred/DeferredUpdates.php(201): MediaWiki\Deferred\DeferredUpdates::attemptUpdate(MediaWiki\Deferred\TransactionRoundDefiningUpdate)
14:55:18 mw-dberror.log:#19 /workspace/src/includes/deferred/DeferredUpdates.php(288): MediaWiki\Deferred\DeferredUpdates::run(MediaWiki\Deferred\TransactionRoundDefiningUpdate)
14:55:18 mw-dberror.log:#20 /workspace/src/includes/deferred/DeferredUpdatesScope.php(243): MediaWiki\Deferred\DeferredUpdates::MediaWiki\Deferred\{closure}(MediaWiki\Deferred\TransactionRoundDefiningUpdate, int)
14:55:18 mw-dberror.log:#21 /workspace/src/includes/deferred/DeferredUpdatesScope.php(172): MediaWiki\Deferred\DeferredUpdatesScope->processStageQueue(int, int, Closure)
14:55:18 mw-dberror.log:#22 /workspace/src/includes/deferred/DeferredUpdates.php(307): MediaWiki\Deferred\DeferredUpdatesScope->processUpdates(int, Closure)
14:55:18 mw-dberror.log:#23 /workspace/src/includes/MediaWikiEntryPoint.php(670): MediaWiki\Deferred\DeferredUpdates::doUpdates()
14:55:18 mw-dberror.log:#24 /workspace/src/includes/MediaWikiEntryPoint.php(492): MediaWiki\MediaWikiEntryPoint->restInPeace()
14:55:18 mw-dberror.log:#25 /workspace/src/includes/MediaWikiEntryPoint.php(450): MediaWiki\MediaWikiEntryPoint->doPostOutputShutdown()
14:55:18 mw-dberror.log:#26 /workspace/src/includes/MediaWikiEntryPoint.php(207): MediaWiki\MediaWikiEntryPoint->postOutputShutdown()
14:55:18 mw-dberror.log:#27 /workspace/src/index.php(58): MediaWiki\MediaWikiEntryPoint->run()
14:55:18 mw-dberror.log:#28 {main}

with URL /index.php?title=Special:Redirect/file/Mamoul_biscotti_libanesi.jpg&width=16 which is even more confusing - that shouldn't even do any writes.

Change #1190307 had a related patch set uploaded (by Daimona Eaytoy; author: Daimona Eaytoy):

[mediawiki/core@master] Revert "User: Reduce locking severity of ::getInstanceForUpdate()"

https://gerrit.wikimedia.org/r/1190307

Since this is affecting multiple repos, I have created a revert of the core change, so that we can unblock CI for everyone affected while working on a proper fix. I'm going to let it sit for ~half an hour (and complete CI) in case someone is close to pushing a better fix, in which case please let me know.

Change #1190307 merged by jenkins-bot:

[mediawiki/core@master] Revert "User: Reduce locking severity of ::getInstanceForUpdate()"

https://gerrit.wikimedia.org/r/1190307

This affect some of our patches at the moment, do you plan to schedule a backport for the fix before the train catch up? otherwise we will need to wait until next week to merge our patch.

UPDATE: ok, this works after several times of +2 and recheck. Thanks a lot.

@Tgr What do you think of introducing a new method called $user->getInstanceLatest(); and migrate most calls to that (except user_editcount update which would stay with getInstanceForUpdate()). I think that would be a good compromise between this bug and {T405112}

With no locking at all.

Change #1190612 had a related patch set uploaded (by Ladsgroup; author: Amir Sarabadani):

[mediawiki/core@master] ApiOptionsBase: Don't lock the user row

https://gerrit.wikimedia.org/r/1190612

@Tgr What do you think of introducing a new method called $user->getInstanceLatest(); and migrate most calls to that (except user_editcount update which would stay with getInstanceForUpdate()).

Yeah I was thinking the same, done in https://gerrit.wikimedia.org/r/c/mediawiki/core/+/1190625.

Do we want to backport rMW3a52a5fe87af: User: Reduce locking severity of ::getInstanceForUpdate() to wmf.20 as a temporary measure? Or does {df6ca4913812c06ba94f201bd4c1a1de27b6d4e1} obsolete it?

Change #1190612 abandoned by Ladsgroup:

[mediawiki/core@master] ApiOptionsBase: Don't lock the user row

Reason:

Done by Iffea7ffdf5cc

https://gerrit.wikimedia.org/r/1190612

I'll backport your patch to wmf.20. We should start after this to replace usages.

The patch causing the CI break was reverted on master, and now on wmf.19 as well, so I think we can close this.