module TransactionReliability
Provide utilities for the (more) reliable handling of database errors related to concurrency or connectivity.
Currently only handles Postgresql and Mysql, assuming use of the PG and Mysql2 drivers respectively
Constants
- SQLSTATE_CONNECTION_ERRORS
- SQLSTATE_DEADLOCK_ERRORS
- SQLSTATE_ISOLATION_ERRORS
- VERSION
Public Class Methods
rewrap_exception(exception)
click to toggle source
Unwrap ActiveRecord::StatementInvalid into some more specific exceptions that we define.
Only defined for Mysql2 and PG drivers at the moment
# File lib/transaction_reliability.rb, line 149 def self.rewrap_exception(exception) if exception.message.start_with?('PG::') || exception.class.name.start_with?('PG::') rewrap_pg_exception exception elsif exception.message =~ /^mysql2::/i rewrap_mysql2_exception exception else exception end end
Protected Class Methods
rewrap_mysql_exception(exception)
click to toggle source
Ugh. This may not work if you're using non-English localization for your MySQL server.
# File lib/transaction_reliability.rb, line 216 def self.rewrap_mysql_exception(exception) orig = exception.original_exception message = exception.message case when message =~ /Serialization failure/i SerializationFailure.new(message, orig) when message =~ /Deadlock found when trying to get lock/i || message =~ /Lock wait timeout exceeded/i DeadlockDetected.new(message, orig) when message =~ /Lost connection to MySQL server/i || message =~ /Invalid connection handle/i || message =~ /MySQL server has gone away/i || message =~ /Broken pipe/i || message =~ /Server shutdown in progress/i ConnectionLost.new(message, orig) else exception end end
rewrap_pg_exception(exception)
click to toggle source
# File lib/transaction_reliability.rb, line 183 def self.rewrap_pg_exception(exception) message = exception.message orig = case when exception.is_a?(PG::Error) exception when exception.respond_to?(:original_exception) exception.original_exception else exception end if orig.is_a? PG::Error sqlstate = orig.result.result_error_field(PGresult::PG_DIAG_SQLSTATE) rescue nil else sqlstate = nil end case when orig.is_a?(PG::ConnectionBad) || SQLSTATE_CONNECTION_ERRORS.include?(sqlstate) ConnectionLost.new(message, orig) when orig.is_a?(PG::TRDeadlockDetected) || SQLSTATE_DEADLOCK_ERRORS.include?(sqlstate) DeadlockDetected.new(message, orig) when orig.is_a?(PG::TRSerializationFailure) || SQLSTATE_ISOLATION_ERRORS.include?(sqlstate) SerializationFailure.new(message, orig) else exception end end