def with_transaction_retry(options = {})
      retry_count         = options.fetch(:retry_count,            4)
      backoff             = options.fetch(:backoff,             0.25)
      exit_on_fail        = options.fetch(:exit_on_fail,       false)
      exit_on_disconnect  = options.fetch(:exit_on_disconnect,  true)

      count               = 0

      # list of exceptions we may catch
      exceptions = ['ActiveRecord::StatementInvalid', 'PG::Error', 'Mysql2::Error'].
                     map {|name| name.safe_constantize}.
                     compact

      #
      # There are times when, for example, 
      # a raw PG::Error is throw rather than a wrapped ActiveRecord::StatementInvalid
      #
      # Also, connector-specific classes like PG::Error may not be defined
      #
      begin
        connection_lost = false
        yield
      rescue *exceptions => e
        translated = TransactionReliability.rewrap_exception(e)

        case translated
          when ConnectionLost
            (options[:connection] || ActiveRecord::Base.connection).reconnect!
            connection_lost = true
          when DeadlockDetected, SerializationFailure
          else
            raise translated
        end

        # Retry up to retry_count times
        if count < retry_count
          sleep backoff
          count   += 1
          backoff *= 2
          retry
        else
          if (connection_lost && exit_on_disconnect) || exit_on_fail
            exit
          else 
            raise(translated)
          end
        end
      end
    end
def with_transaction_retry(options = {})
      retry_count         = options.fetch(:retry_count,            4)
      backoff             = options.fetch(:backoff,             0.25)
      exit_on_fail        = options.fetch(:exit_on_fail,       false)
      exit_on_disconnect  = options.fetch(:exit_on_disconnect,  true)

      count               = 0

      # list of exceptions we may catch
      exceptions = ['ActiveRecord::StatementInvalid', 'PG::Error', 'Mysql2::Error'].
                     map {|name| name.safe_constantize}.
                     compact

      #
      # There are times when, for example, 
      # a raw PG::Error is throw rather than a wrapped ActiveRecord::StatementInvalid
      #
      # Also, connector-specific classes like PG::Error may not be defined
      #
      begin
        connection_lost = false
        yield
      rescue *exceptions => e
        translated = TransactionReliability.rewrap_exception(e)

        case translated
          when ConnectionLost
            (options[:connection] || ActiveRecord::Base.connection).reconnect!
            connection_lost = true
          when DeadlockDetected, SerializationFailure
          else
            raise translated
        end

        # Retry up to retry_count times
        if count < retry_count
          sleep backoff
          count   += 1
          backoff *= 2
          retry
        else
          if (connection_lost && exit_on_disconnect) || exit_on_fail
            exit
          else 
            raise(translated)
          end
        end
      end
    end
Intended to be included in an ActiveRecord model class.

 Retries a block (which usually contains a transaction) under certain
 failure conditions, up to a configurable number of times with an
 exponential backoff delay between each attempt.

 Conditions for retrying:

    1. Database connection lost
    2. Query or txn failed due to detected deadlock
       (Mysql/InnoDB and Postgres can both signal this for just about
        any transaction)
    3. Query or txn failed due to serialization failure
       (Postgres will signal this for transactions in isolation
        level SERIALIZABLE)

 options:
    retry_count  - how many retries to make; default 4

    backoff      - time period before 1st retry, in fractional seconds.
                   will double at every retry. default 0.25 seconds.

    exit_on_disconnect
                 - whether to call exit if no retry succeeds and
                   the cause is a failed connection

    exit_on_fail - whether to call exit if no retry succeeds

 defaults: