So, Rails4 added support for setting the transaction isolation level on transactions. Something Rails has needed sorely for a long time.
Unfortunately nowhere is it documented how to correctly detect if a Transaction has failed during your Transaction block (vs any other kind of error, such as constraints failures).
The right way seems to be:
RetryLimit = 5 # set appropriately... txn_retry_count = 0 begin Model.transaction(isolation: :serializable) do # do txn stuff here. end rescue ActiveRecord::StatementInvalid => err if err.original_exception.is_a?(PG::TransactionRollback) txn_retry_count += 1 if txn_retry_count < RetryLimit retry else raise end else raise end end
The transaction concurrency errors are all part of a specific family, which the current stable
pg gem correctly reproduces in it’s exception heirachy. However, ActiveRecord captures the exception and raises it as a statement error, forcing you to unwrap it one layer in your code.