BigBinary Blog

We write about Ruby on Rails, React.js, React Native, remote work, open source, engineering and design.

Rails 6.1 deprecates the use of exit statements in transaction

This blog is part of our Rails 6.1 series.

Rails 6.1 deprecates the use of return, break or throw to exit a transaction block.

return / break

1>> Post.transaction do
2>>   @post.update(post_params)
3>>
4>>   break # or return
5>> end
6
7# => TRANSACTION (0.1ms)  begin transaction
8# => DEPRECATION WARNING: Using `return`, `break` or `throw` to exit a transaction block is
9# => deprecated without replacement. If the `throw` came from
10# => `Timeout.timeout(duration)`, pass an exception class as a second
11# => argument so it doesn't use `throw` to abort its block. This results
12# => in the transaction being committed, but in the next release of Rails
13# => it will rollback.
14# => TRANSACTION (0.8ms)  commit transaction

throw

1>> Timeout.timeout(1) do
2>>   Post.transaction do
3>>     @post.update(post_params)
4>>
5>>     sleep 3 # simulate slow request
6>>   end
7>> end
8
9# => TRANSACTION (0.1ms)  begin transaction
10# => DEPRECATION WARNING: Using `return`, `break` or `throw` to exit a transaction block is
11# => deprecated without replacement. If the `throw` came from
12# => `Timeout.timeout(duration)`, pass an exception class as a second
13# => argument so it doesn't use `throw` to abort its block. This results
14# => in the transaction being committed, but in the next release of Rails
15# => it will rollback.
16# => TRANSACTION (1.6ms)  commit transaction
17# => Completed 500 Internal Server Error in 1022ms (ActiveRecord: 3.2ms | Allocations: 9736)
18# => Timeout::Error (execution expired)

Here, even when the error was thrown the transaction is committed. This is something which is going to change in the future versions.

This is done because currently, when a transaction block is wrapped in Timeout.timeout(duration) i.e. without second argument(an exception class) then it uses throw to exit the transaction.

Solution

1>> Timeout.timeout(1, Timeout::Error) do
2>>   Post.transaction do
3>>     @post.update(post_params)
4>>
5>>     sleep 3 # simulate slow request
6>>   end
7>> end
8
9# => TRANSACTION (0.1ms)  begin transaction
10# => TRANSACTION (0.7ms)  rollback transaction
11# => Timeout::Error (execution expired)

Check out the pull request for more details on this.

Sandip Mane in Rails 6.1
August 4, 2020
Share

Subscribe to our newsletter