Page MenuHomePhabricator

DeferredUpdates should not be enqueued while inside a database transaction.
Open, MediumPublic

Description

Enqueueing a DeferredUpdate while in a database transaction is problematic, because the DeferredUpdate may encounter an unexpected situation if the transaction is rolled back, but the update is kept in the queue and executed later in the request. For instance, a likely explanation for the exception thrown by LinksUpdate in T279832 is that the original transaction was rolled back, and the newly created page that the LinksUpdate was supposed to operate on was never committed to the database.

To avoid this, we could:

  • Forbid DeferredUpdates being scheduled in a transaction. Existing code would need to be modified to accommodate this restriction, e.g. using IDatabase::onTransactionIdle callbacks or by converting to AutoCommitUpdate or MWCallableUpdate, which have rollback handling built in.
  • Automatically de-queue all updates enqueued during a transaction, similar to the mechanism used by AutoCommitUpdate.
  • Automatically postpone enqueueing updates until after the current transaction, using onTransactionIdle.

Event Timeline

Change 683251 had a related patch set uploaded (by Daniel Kinzler; author: Daniel Kinzler):

[mediawiki/core@master] DeferredUpdates: never enqueue updates during a transaction

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

A lighter approach would be to make sure all kinds of deferred updates can be manually tied to a transaction so they get cancelled on rollback. That would be quite useful for e.g. JobQueue::lazyPush() (which internally uses a deferred).