verifiable_registry.rb 3.47 KB
Newer Older
1 2
# frozen_string_literal: true

3 4 5
module Geo
  module VerifiableRegistry
    extend ActiveSupport::Concern
6
    extend ::Gitlab::Utils::Override
7
    include ::Gitlab::Geo::VerificationState
8 9 10 11 12 13 14 15 16 17 18 19 20

    class_methods do
      extend ::Gitlab::Utils::Override

      # Overrides a method in `Gitlab::Geo::VerificationState`. This method is
      # used by `Gitlab::Geo::VerificationState.start_verification_batch` to
      # produce a query which must return values of the primary key of the
      # *model*, not of the *registry*. We need this so we can instantiate
      # Replicators.
      override :verification_state_model_key
      def verification_state_model_key
        self::MODEL_FOREIGN_KEY
      end
21

22 23 24 25
      override :verification_pending_batch_relation
      def verification_pending_batch_relation(batch_size:)
        super.synced
      end
26

27 28 29 30
      override :verification_failed_batch_relation
      def verification_failed_batch_relation(batch_size:)
        super.synced
      end
31

32 33 34 35
      override :needs_verification_relation
      def needs_verification_relation
        super.synced
      end
36
    end
37

38 39
    included do
      extend ::Gitlab::Utils::Override
40

41
      sha_attribute :verification_checksum_mismatched
42

43
      scope :available_verifiables, -> { all }
44

45 46 47
      override :clear_verification_failure_fields!
      def clear_verification_failure_fields!
        super
48

49 50 51 52 53 54
        # Note: If the return value of a `before_transition` block is `false`,
        # then the transition is halted. Anything else, including `nil`, does not
        # halt the transition.
        self.checksum_mismatch = false
        self.verification_checksum_mismatched = nil
      end
55

56 57 58 59 60 61
      # Records a checksum mismatch
      #
      # @param [String] checksum value which does not match the primary checksum
      def verification_failed_due_to_mismatch!(checksum, primary_checksum)
        message = 'Checksum does not match the primary checksum'
        details = { checksum: checksum, primary_checksum: primary_checksum }
62

63
        log_info(message, details)
64

65 66 67 68
        self.verification_failure = "#{message} #{details}".truncate(255)
        self.verification_checksum = checksum
        self.verification_checksum_mismatched = checksum
        self.checksum_mismatch = true
69

70 71
        self.verification_failed!
      end
72

73
      private
74

75 76 77 78 79
      override :track_checksum_result!
      def track_checksum_result!(checksum, calculation_started_at)
        unless replicator.matches_checksum?(checksum)
          return verification_failed_due_to_mismatch!(checksum, replicator.primary_checksum)
        end
80

81 82
        verification_succeeded_with_checksum!(checksum, calculation_started_at)
      end
83
    end
84 85 86 87 88

    override :after_synced
    def after_synced
      self.verification_pending!
    end
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106

    override :before_verification_failed
    def before_verification_failed
      # Let verification failure fields get set as usual
      super

      # When this registry became synced, retry_count was set to 0. This line
      # ensures that resyncs due to verification failures use progressive
      # backoff behavior. One is subtracted to compensate for 1 being
      # automatically added to `retry_count` on transition to failed.
      self.retry_count = self.verification_retry_count - 1

      self.last_sync_failure = "Verification failed with: #{verification_failure}".truncate(255)

      # This registry was successfully synced, and now it has failed
      # verification. This line makes Geo automatically resync it.
      self.failed
    end
107 108
  end
end