Categories
Software Development

Detecting Transaction Failures in Rails (with PostgreSQL)

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.