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:
[ruby]
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
[/ruby]
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.