Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do rails Transactions blocks exit after all actions have been committed?

Related to Run rails code after an update to the database has commited, without after_commit, but I think deserving its own question.

If I have code like this:

my_instance = MyModel.find(1)
MyModel.transaction do 
  my_instance.foo = "bar"
  my_instance.save!
end
new_instance = MyModel.find(1)
puts new_instance.foo

Is this a guarantee that new_instance.foo will always output "bar" and not its previous value? I'm looking for a way to ensure that all the database actions that occur in a previous statement are committed BEFORE executing my next statements. Rails has an after_commit hook for this, but I don't want this code executed every time... only in this specific context.

I can't find anything in the documentation on Transactions that would indicate if Transaction blocks are "blocking". If they are blocking, that will satisfy my requirement. Unfortunately, I can't think of a practical way to test this behavior to confirm my suspicions one way or another.

like image 855
Brian Avatar asked Oct 16 '25 03:10

Brian


1 Answers

Still researching this, but I think a transaction does block code execution until after the database confirms that it has written. Since "save!" is automatically wrapped in a transaction by Rails, the relevant code should run synchronously. The extra transaction block should be unnecessary.

I don't think Rails returns as soon as it hands off the call to the DB when the DB calls are within a transaction. The confusion I had was with after_save callbacks. After_save callbacks suffer from race conditions because they are in fact part of the transaction that saves are automatically wrapped in, so any code called by an after_save callback is not race condition safe, it is not protected by the transaction. Only after_commit calls are safe. Within the transaction Rails will hand off to the DB and then execute after_save callbacks before the DB has finished committing.

Studying this for more insights:

https://github.com/rails/rails/blob/bfdd3c2182156fa2cb81ed4f048b065a2d6f1341/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb

UPDATE

Changing my answer to "no". It doesn't appear that save! or save blocks execution. From these two resources, looks like this is a common problem:

https://github.com/resque/resque/wiki/FAQ#how-do-you-make-a-resque-job-wait-for-an-activerecord-transaction-commit

https://blog.engineyard.com/2011/the-resque-way

like image 148
Ben Avatar answered Oct 18 '25 17:10

Ben



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!