1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Merge pull request #25107 from Erol/introduce-new-ar-transaction-error-classes

Introduce new ActiveRecord transaction error classes

Closes #26018
This commit is contained in:
Rafael Mendonça França 2016-08-03 07:05:22 -03:00
commit fac9938b91
No known key found for this signature in database
GPG key ID: FC23B6D0F1EEE948
5 changed files with 57 additions and 26 deletions

View file

@ -753,7 +753,7 @@ module ActiveRecord
when ER_DATA_TOO_LONG
ValueTooLong.new(message)
when ER_LOCK_DEADLOCK
TransactionSerializationError.new(message)
DeadlockDetected.new(message)
else
super
end

View file

@ -407,6 +407,7 @@ module ActiveRecord
FOREIGN_KEY_VIOLATION = "23503"
UNIQUE_VIOLATION = "23505"
SERIALIZATION_FAILURE = "40001"
DEADLOCK_DETECTED = "40P01"
def translate_exception(exception, message)
return exception unless exception.respond_to?(:result)
@ -419,7 +420,9 @@ module ActiveRecord
when VALUE_LIMIT_VIOLATION
ValueTooLong.new(message)
when SERIALIZATION_FAILURE
TransactionSerializationError.new(message)
SerializationFailure.new(message)
when DEADLOCK_DETECTED
DeadlockDetected.new(message)
else
super
end

View file

@ -285,14 +285,24 @@ module ActiveRecord
class TransactionIsolationError < ActiveRecordError
end
# TransactionSerializationError will be raised when a transaction is rolled
# TransactionRollbackError will be raised when a transaction is rolled
# back by the database due to a serialization failure or a deadlock.
#
# See the following:
#
# * http://www.postgresql.org/docs/current/static/transaction-iso.html
# * https://dev.mysql.com/doc/refman/5.7/en/error-messages-server.html#error_er_lock_deadlock
class TransactionSerializationError < StatementInvalid
class TransactionRollbackError < StatementInvalid
end
# SerializationFailure will be raised when a transaction is rolled
# back by the database due to a serialization failure.
class SerializationFailure < TransactionRollbackError
end
# DeadlockDetected will be raised when a transaction is rolled
# back by the database when a deadlock is encountered.
class DeadlockDetected < TransactionRollbackError
end
# IrreversibleOrderError is raised when a relation's order is too complex for

View file

@ -27,32 +27,25 @@ module ActiveRecord
@connection.drop_table 'samples', if_exists: true
end
test "raises error when a serialization failure occurs" do
assert_raises(ActiveRecord::TransactionSerializationError) do
test "raises DeadlockDetected when a deadlock is encountered" do
assert_raises(ActiveRecord::DeadlockDetected) do
s1 = Sample.create value: 1
s2 = Sample.create value: 2
thread = Thread.new do
Sample.transaction isolation: :serializable do
Sample.delete_all
10.times do |i|
sleep 0.1
Sample.create value: i
end
end
end
sleep 0.1
Sample.transaction isolation: :serializable do
Sample.delete_all
10.times do |i|
sleep 0.1
Sample.create value: i
end
Sample.transaction do
s1.lock!
sleep 1
s2.update_attributes value: 1
end
end
sleep 0.5
Sample.transaction do
s2.lock!
sleep 1
s1.update_attributes value: 2
end
thread.join

View file

@ -26,9 +26,9 @@ module ActiveRecord
@connection.drop_table 'samples', if_exists: true
end
test "raises error when a serialization failure occurs" do
test "raises SerializationFailure when a serialization failure occurs" do
with_warning_suppression do
assert_raises(ActiveRecord::TransactionSerializationError) do
assert_raises(ActiveRecord::SerializationFailure) do
thread = Thread.new do
Sample.transaction isolation: :serializable do
Sample.delete_all
@ -51,8 +51,33 @@ module ActiveRecord
Sample.create value: i
end
end
thread.join
end
end
end
test "raises DeadlockDetected when a deadlock is encountered" do
with_warning_suppression do
assert_raises(ActiveRecord::DeadlockDetected) do
s1 = Sample.create value: 1
s2 = Sample.create value: 2
thread = Thread.new do
Sample.transaction do
s1.lock!
sleep 1
s2.update_attributes value: 1
end
end
sleep 0.5
Sample.transaction do
s2.lock!
sleep 1
s1.update_attributes value: 2
end
thread.join