Rails 6.1 deprecates the use of exit statements in transaction

Sandip Mane

Sandip Mane

August 4, 2020

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.

If this blog was helpful, check out our full blog archive.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.