@@ -10,21 +10,44 @@ module TransactionManagerMonkeyPatch
1010 # exceeded.
1111 def within_new_transaction ( isolation : nil , joinable : true , attempts : 0 )
1212 super ( isolation : isolation , joinable : joinable )
13+ rescue ActiveRecord ::ConnectionNotEstablished => error
14+ raise unless retryable? error
15+ raise if attempts >= @connection . max_transaction_retries
16+
17+ sleep_rand_seconds ( attempts )
18+
19+ unless @connection . active?
20+ warn "connection isn't active, reconnecting"
21+ @connection . reconnect!
22+ end
23+
24+ within_new_transaction ( isolation : isolation , joinable : joinable , attempts : attempts + 1 ) { yield }
1325 rescue ActiveRecord ::StatementInvalid => error
1426 raise unless retryable? error
1527 raise if attempts >= @connection . max_transaction_retries
1628
17- attempts += 1
18- sleep_seconds = ( 2 ** attempts + rand ) / 10
19- sleep ( sleep_seconds )
20- within_new_transaction ( isolation : isolation , joinable : joinable , attempts : attempts ) { yield }
29+ sleep_rand_seconds ( attempts )
30+
31+ within_new_transaction ( isolation : isolation , joinable : joinable , attempts : attempts + 1 ) { yield }
2132 end
2233
2334 def retryable? ( error )
35+ return true if serialization_error? ( error )
2436 return true if error . is_a? ActiveRecord ::SerializationFailure
2537 return retryable? error . cause if error . cause
2638 false
2739 end
40+
41+ def serialization_error? ( error )
42+ errors = [ error ]
43+ errors << error . cause if error . cause
44+ errors . any? { |e | e . is_a? PG ::TRSerializationFailure }
45+ end
46+
47+ def sleep_rand_seconds ( attempts )
48+ sleep_seconds = ( 2 ** attempts + rand ) / 10
49+ sleep ( sleep_seconds )
50+ end
2851 end
2952 end
3053
0 commit comments