Sha256: 3a4332eee716f261a8516a9ed19550011ead98a4080de967fa3404eca69ecd2e

Contents?: true

Size: 1.98 KB

Versions: 4

Compression:

Stored size: 1.98 KB

Contents

# frozen_string_literal: true

module TrxExt
  module Retry
    class << self
      # Wraps specified method in a +TrxExt::Retry.retry_until_serialized+ loop.
      #
      # @param klass [Class] class a method belongs to
      # @param method [Symbol] instance method that needs to be wrapped into +TrxExt::Retry.retry_until_serialized+
      def with_retry_until_serialized(klass, method)
        module_to_prepend = Module.new do
          klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
            def #{method}(...)
              ::TrxExt::Retry.retry_until_serialized do
                super
              end
            end
          RUBY
        end
        prepend module_to_prepend
        method
      end

      # Retries block execution until serialization errors are no longer raised
      def retry_until_serialized
        retries_count = 0
        begin
          yield
        rescue => error
          error_classification = error_classification(error)
          if error_classification == :record_not_unique
            retries_count += 1
          end
          if retry_query?(error, retries_count)
            TrxExt.log("Detected transaction rollback condition. Reason - #{error_classification}. Retrying...")
            retry
          else
            raise error
          end
        end
      end

      private

      def error_classification(error)
        case
        when error.message.index('deadlock detected')
          :deadlock
        when error.message.index('could not serialize')
          :serialization_error
        when error.class == ActiveRecord::RecordNotUnique
          :record_not_unique
        end
      end

      def retry_query?(error, retryies_count)
        classification = error_classification(error)
        ActiveRecord::Base.connection.open_transactions == 0 &&
          (%i(deadlock serialization_error).include?(classification) ||
            classification == :record_not_unique && retryies_count < TrxExt.config.unique_retries)
      end
    end
  end
end

Version data entries

4 entries across 4 versions & 1 rubygems

Version Path
trx_ext-1.0.3 lib/trx_ext/retry.rb
trx_ext-1.0.2 lib/trx_ext/retry.rb
trx_ext-1.0.1 lib/trx_ext/retry.rb
trx_ext-1.0.0 lib/trx_ext/retry.rb