Problem/Motivation
Right now, most transactions in Drupal core are COMMITed or a RELEASEd SAVEPOINT only when their Transaction object goes out of scope. In practice, it's an autocommit.
This has caused, along time, several issues - see #1025314: Transactions should be allowed to be committed explicitly for a lot of rationale on why this is not optimal. More recently, usage of xdebug is impaired and not solved yet when transaction are involved - see #3405976: Transaction autocommit during shutdown relies on unreliable object destruction order (xdebug 3.3+ enabled).
In the parent issue we introduced the possibility to explicitly commit Transaction objects.
Xdebug testing
Manual testing an environment with xdebug 3.3 or greater enabled to make sure that we do not get any longer failures related to the unpredictable object destruction sequence. xdebug should be in develop mode, not debug mode for testing.
Potential testing scenarios from #3405976: Transaction autocommit during shutdown relies on unreliable object destruction order (xdebug 3.3+ enabled):
- @pacproduct: Our installation process is entirely run on command-line via Drush commands, and one of them (applying a recipe:
ddev recipe-apply recipes/our_recipeddev drush recipe ../recipes/name-of-recipe) fails right at the end with the following error.... - @joelpittet: working on a test in og module (potentially this is from reviewing a MR that became og_migrate).
Proposed resolution
In this issue we convert all Drupal core transactions to use explicit commit.
In follow ups:
- #3584238: Deprecate implicit commit-on-destruct
- Deprecate implicit commit on Transaction destruction.
- Deprecate for removal the methods introduced in #3405976: Transaction autocommit during shutdown relies on unreliable object destruction order (xdebug 3.3+ enabled):
Connection::commitAll()Database::commitAllOnShutdown()TransactionManagerBase::commitAll()
- #3583849: Deprecate PgSql Connection::*Savepoint() methods Deprecate the following methods in
Drupal\pgsql\Driver\Database\pgsql\Connection:::addSavepoint()::releaseSavepoint()::rollbackSavepoint()
Remaining tasks
User interface changes
No
API changes
No
Data model changes
No
Release notes snippet
| Comment | File | Size | Author |
|---|
Issue fork drupal-3406985
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3406985-only-convert
changes, plain diff MR !15375
- 3406985-pp-1-convert-all
changes, plain diff MR !5738
Comments
Comment #5
mondrakeComment #6
mondrakeComment #11
mondrakeComment #12
nicxvan commentedIt would be helpful to have a small summary on the why in the issue summary
Comment #13
mondrakeBlocker is in, tagging per #12.
Comment #14
mondrakeUpdated IS.
Comment #15
mondrakeSome point were raised in Slack https://drupal.slack.com/archives/C1BMUQ9U6/p1747310837078309
Comment #16
mondrakemade suggested changes, thanks @alexpott
Comment #17
mondrakeAdded specific deprecation tests for the implicit commit behavior and for ::commitAll() when there are pending transactions open.
Comment #18
smustgrave commentedFeedback appears to be addressed but CR is still tbd
Comment #19
mondrakeFleshed the CR
Comment #20
mondrakePer https://drupal.slack.com/archives/C1BMUQ9U6/p1747310372256759?thread_ts=..., the MR could use some manual testing to check that with xdebug 3.3+ enabled we do not get any longer failures related to the unpredictable object destruction sequence.
Comment #21
mondrakeAddressed review comments.
Comment #22
mradcliffeCurrent test failures are deprecations for
1) /builds/issue/drupal-3406985/core/lib/Drupal/Core/Test/HttpClientMiddleware/TestHttpClientMiddleware.php:52
Database commit by letting a Transaction object go out of scope is deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. Commit explicitly via Transaction::commitOrRelease() instead. See https://www.drupal.org/node/3524461
1) /builds/issue/drupal-3406985/core/lib/Drupal/Core/Database/Transaction/TransactionManagerBase.php:364
Database commit by letting a Transaction object go out of scope is deprecated in drupal:11.3.0 and is removed from drupal:13.0.0. Commit explicitly via Transaction::commitOrRelease() instead. See https://www.drupal.org/node/3524461
Uploaded as a text file after parsing through Functional and FunctionalJavaScript test results. Summarized as
- locale
- config_translation
- AssetOptimizationUmamiTest
- help
- demo_umami
- core Installer tests
Comment #23
mondrakeSome recent commits may have added deprecated behaviour. Needs sorting out which. On that.
Comment #24
mondrakeCulprit was #3520750: Use a transaction PoDatabaseWriter to improve performance. But that helped proving that deprecation of implicit commit works.
Comment #25
mradcliffeI added some manual testing scenarios for xdebug 3.3+ in develop mode.
Comment #26
smustgrave commentedWith regards to #20 any suggestion on how to test that?
Comment #27
mondrake@ceonizm confirmed that the MR here fixes #3538834: Error at the end of any PHPunit test
Comment #28
mondrakeComment #29
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #30
mondrakerebased
Comment #31
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #32
mondrakeComment #33
ghost of drupal pastComment #34
mondrakeComment #35
mondrakeComment #36
godotislateAre there an easily reproducible steps with XDebug enabled in
developmode to test this? I've read through the examples in the IS, as well as comments from #3405976: Transaction autocommit during shutdown relies on unreliable object destruction order (xdebug 3.3+ enabled) and #3451460: Sessions are invalidated on subsequent page request when written while transaction is open, but reproducing seems to be non-trivial or requires contrib or custom code that's not specified.Meanwhile, the references to 11.3.0 in the deprecation messages need updating to 11.4.0, and the version set in the CR needs updating as well.
Comment #37
mondrakeLet's fix that when someone is ready to RTBC the issue.
Comment #38
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #39
mondrakeMerged with main; a conflict in PgSQL Insert class to resolve after a0acc2c1005d9470745f140672d70c0905494212
Comment #40
godotislateI've found some test steps with consistently repeatable failures that the changes in the MR here do not solve. It seems related, but not I'm not completely sure. I can file a separate issue if appropriate.
Local env:
DDEV v1.24.10
Using ddev-core-dev add-on: https://github.com/justafish/ddev-drupal-core-dev
DB version SQLite 3.45.1
Xdebug v3.5.0
xdebug.mode = develop
PHP 8.5.2
Steps:
Checkout MR branch
Install Drupal core with standard:
ddev drush si standard -yUninstall Toolbar
ddev drush pmu toolbarInstall Navigation
ddev drush en navigation -yEnable Xdebug
ddev xdebugRebuild cache
ddev drush crObserve exception:
Note that if Xdebug is not enabled, or Xdebug mode is "debug" or if Navigation is uninstalled, the exception is not thrown. I don't know if this is SQLite specific, because I haven't tested on MySQL or Mariadb.
Comment #41
mondrakeThanks @godotislate, I think #40 is very much overlapping with #3569316: Client connection ($clientConnection) must be of type object, null given when deleting a node.
IMHO what we are facing here is that currently not only we execute database transaction commits in the object destruction danger zone, but that we also execute post-commit callbacks once the commit is completed, in the same danger zone. @ålexpott already identified this as risky business in #3447097-10: TransactionNameNonUniqueException: A transaction named drupal_transaction is already in use.
For me (I am repeating myself), the way out is the plan in #3495728: [meta] Drop implicit autocommit on Transaction destruction: here we take away the transaction commit from the danger zone, so that they are executed during normal runtime based on the explicit call to
::commitOrRelease(). In follow ups, we will do the same for the post-transaction callbacks, moving their execution from the object destruction time to post::commitOrRelease(). In the plan I am suggesting to use events for that, but we can consider alternatives of course.Comment #42
mondrakeDone that.
Comment #43
godotislateI would like to help get this to RTBC, but I don't think I understand the DB layer well enough to do so without having repeatable test steps that show what this solves.
Comment #44
mondrake#43 of course, thanks anyway.
In general, this issue is not trying to ‘solve’ any bug. If it does, it’s incidental. There are plenty of issues open already about bugs with transactions on destruction.
This is ‘simply’ implementing across core the explicit commit feature already introduced in the parent issue, and deprecating (but not fixing bugs for) commit on destruction.
Comment #46
mondrakeIn the hope to move things forward, I have opened MR!15375 with a minimal scope - only convert Drupal core transactions to use explicit commit. That leaves deprecations for a later stage.
Comment #48
mondrakeComment #49
mondrakeNo longer needs manual testing with new, reduced, scope - that may be relevant in followups to check xdebug behaviour.
Comment #50
mradcliffeI set the primary issue for the change record draft to the meta for now. I don’t think we should publish the change record until after the deprecation issue, right?
Comment #51
mondrake#50 good points, +1
Comment #52
mondrakeFiled #3583849: Deprecate PgSql Connection::*Savepoint() methods.
Comment #53
godotislateI don't have a deep understanding of the DB layer, but the MR seems straightforward from the explanation/goals defined in the IS. I do have a couple general questions and one small punctuation nit.
Comment #54
mondrakeThanks. Applied suggestion and replied to comment inline.
Comment #55
godotislateThanks for the explanation. This makes sense to me.
Comment #56
mondrakeComment #60
amateescu commentedI see that no one replied to @ghost of drupal past's question from #33, so I've read #301049: Transaction nesting not tracked by connection, and, as far as I can see from the patch that was committed there, the primary goal of that issue was transaction nesting, which is fully preserved by
commitOrRelease()(it works through the same stack mechanism). The "prohibition" of explicit commits in that patch was a safeguard against bypassing the nesting layer via rawPDO::commit(), not a design goal in itself.The new mechanism for explicit commits were discussed and agreed upon in #1025314: Transactions should be allowed to be committed explicitly and especially #3398767: Allow returning explicitly to the prior nesting level in transactions (aka allow explicit COMMIT in Transaction objects), where
commitOrRelease()was introduced.I've read this MR a few times already in the past few weeks, and the smaller scope is appreciated :)
Committed and pushed 8d78571bbef to main and 3c48dc8cccc to 11.x. Thanks!
Comment #63
amateescu commentedNote that I haven't published the change record, I think that should be done in #3584238: Deprecate implicit commit-on-destruct.