Module: ActiveRecord::ConnectionAdapters::CockroachDB::TransactionManagerMonkeyPatch

Included in:
TransactionManager
Defined in:
lib/active_record/connection_adapters/cockroachdb/transaction_manager.rb

Instance Method Summary collapse

Instance Method Details

#retryable?(error) ⇒ Boolean

Returns:

  • (Boolean)
[View source]

34
35
36
37
38
39
# File 'lib/active_record/connection_adapters/cockroachdb/transaction_manager.rb', line 34

def retryable?(error)
  return true if serialization_error?(error)
  return true if error.is_a? ActiveRecord::SerializationFailure
  return retryable? error.cause if error.cause
  false
end

#serialization_error?(error) ⇒ Boolean

Returns:

  • (Boolean)
[View source]

41
42
43
44
45
# File 'lib/active_record/connection_adapters/cockroachdb/transaction_manager.rb', line 41

def serialization_error?(error)
  errors = [error]
  errors << error.cause if error.cause
  errors.any? {|e| e.is_a? PG::TRSerializationFailure }
end

#sleep_rand_seconds(attempts) ⇒ Object

[View source]

47
48
49
50
# File 'lib/active_record/connection_adapters/cockroachdb/transaction_manager.rb', line 47

def sleep_rand_seconds(attempts)
  sleep_seconds = (2 ** attempts + rand) / 10
  sleep(sleep_seconds)
end

#within_new_transaction(isolation: nil, joinable: true, attempts: 0) ⇒ Object

Capture ActiveRecord::SerializationFailure errors caused by transactions that fail due to serialization errors. Failed transactions will be retried until they pass or the max retry limit is exceeded.

[View source]

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/active_record/connection_adapters/cockroachdb/transaction_manager.rb', line 11

def within_new_transaction(isolation: nil, joinable: true, attempts: 0)
  super(isolation: isolation, joinable: joinable)
rescue ActiveRecord::ConnectionNotEstablished => error
  raise unless retryable? error
  raise if attempts >= @connection.max_transaction_retries

  sleep_rand_seconds(attempts)

  unless @connection.active?
    warn "connection isn't active, reconnecting"
    @connection.reconnect!
  end

  within_new_transaction(isolation: isolation, joinable: joinable, attempts: attempts + 1) { yield }
rescue ActiveRecord::StatementInvalid => error
  raise unless retryable? error
  raise if attempts >= @connection.max_transaction_retries

  sleep_rand_seconds(attempts)

  within_new_transaction(isolation: isolation, joinable: joinable, attempts: attempts + 1) { yield }
end