Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Active Record commit transaction on return, break and throw #48600

Merged
merged 1 commit into from Jul 10, 2023

Conversation

casperisfine
Copy link
Contributor

Fix: #45017
Ref: #29333
Ref: ruby/timeout#30

Historically only raised errors would trigger a rollback, but in Ruby 2.3, the timeout library started using throw to interupt execution which had the adverse effect of committing open transactions.

To solve this, in Active Record 6.1 the behavior was changed to instead rollback the transaction as it was safer than to potentially commit an incomplete transaction.

Using return, break or throw inside a transaction block was essentially deprecated from Rails 6.1 onwards.

However with the release of timeout 0.4.0, Timeout.timeout now raises an error again, and Active Record is able to return to its original, less surprising, behavior.

@casperisfine casperisfine force-pushed the transaction-commit-on-return branch 3 times, most recently from 530f945 to ebd724b Compare June 29, 2023 09:17
@casperisfine
Copy link
Contributor Author

@matthewd ok, I think I address most if not all the feedback, the only thing is really the configuring.md, I'm not super inspired, but I can keep it short there if you prefer. Let me know if you have other concerns.

@casperisfine casperisfine force-pushed the transaction-commit-on-return branch 3 times, most recently from bb2b6b7 to dcc543f Compare July 10, 2023 08:07
Fix: rails#45017
Ref: rails#29333
Ref: ruby/timeout#30

Historically only raised errors would trigger a rollback, but in Ruby `2.3`, the `timeout` library
started using `throw` to interupt execution which had the adverse effect of committing open transactions.

To solve this, in Active Record 6.1 the behavior was changed to instead rollback the transaction as it was safer
than to potentially commit an incomplete transaction.

Using `return`, `break` or `throw` inside a `transaction` block was essentially deprecated from Rails 6.1 onwards.

However with the release of `timeout 0.4.0`, `Timeout.timeout` now raises an error again, and Active Record is able
to return to its original, less surprising, behavior.
@byroot
Copy link
Member

byroot commented Jul 10, 2023

Seems we have a bunch of flaky tests on CI, but I don't think they are related to this PR.

@byroot byroot merged commit 7b52f56 into rails:main Jul 10, 2023
8 of 9 checks passed
Comment on lines +1291 to +1293
If set to `false`, it will be rolled back.

If set to `true`, the above transaction will be committed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make this more explicit about what will happen? I think this is what happens, but I'm not sure:

If set to `false`, it will be rolled back, so neither model will save.

If set to `true`, the above transaction will be committed. `model` will save, but `other_model` will not.

@ghiculescu
Copy link
Member

Is it safe to update to timeout 0.4.0 without this change? If not, should we try and alert users somehow? I ran all the tests on 7-0-stable against the latest version of timeout and they all passed, so I think it is safe, but thought it was worth double checking.

@matthewd
Copy link
Member

Is it safe to update to timeout 0.4.0 without this change?

Yes.


| Starting with version | The default value is |
| --------------------- | -------------------- |
| (original) | `false` |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure exactly how to spell it, but perhaps we should distinguish the 6.1 behaviour change in this table somehow, even though the config option under discussion wasn't available at the time? 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ActiveRecord silently triggers a rollback when using return in the transaction block in Rails 7
5 participants