Commit d166eecc authored by Mike Kozono's avatar Mike Kozono

Refactor: Extract VerifiableReplicator concern

from BlobReplicatorStrategy
parent 33a3220f
...@@ -4,7 +4,7 @@ module Geo ...@@ -4,7 +4,7 @@ module Geo
module BlobReplicatorStrategy module BlobReplicatorStrategy
extend ActiveSupport::Concern extend ActiveSupport::Concern
include Delay include ::Geo::VerifiableReplicator
include Gitlab::Geo::LogHelpers include Gitlab::Geo::LogHelpers
included do included do
...@@ -17,7 +17,8 @@ module Geo ...@@ -17,7 +17,8 @@ module Geo
return unless self.class.enabled? return unless self.class.enabled?
publish(:created, **created_params) publish(:created, **created_params)
schedule_checksum_calculation if needs_checksum?
after_verifiable_update
end end
# Called by Gitlab::Geo::Replicator#consume # Called by Gitlab::Geo::Replicator#consume
...@@ -47,45 +48,8 @@ module Geo ...@@ -47,45 +48,8 @@ module Geo
carrierwave_uploader.path carrierwave_uploader.path
end end
def calculate_checksum!
checksum = model_record.calculate_checksum!
update_verification_state!(checksum: checksum)
rescue => e
log_error('Error calculating the checksum', e)
update_verification_state!(failure: e.message)
end
# Check if given checksum matches known one
#
# @param [String] checksum
# @return [Boolean] whether checksum matches
def matches_checksum?(checksum)
model_record.verification_checksum == checksum
end
private private
# Update checksum on Geo primary database
#
# @param [String] checksum value generated by the checksum routine
# @param [String] failure (optional) stacktrace from failed execution
def update_verification_state!(checksum: nil, failure: nil)
retry_at, retry_count = calculate_next_retry_attempt if failure.present?
model_record.update!(
verification_checksum: checksum,
verified_at: Time.current,
verification_failure: failure,
verification_retry_at: retry_at,
verification_retry_count: retry_count
)
end
def calculate_next_retry_attempt
retry_count = model_record.verification_retry_count.to_i + 1
[next_retry_time(retry_count), retry_count]
end
def download def download
::Geo::BlobDownloadService.new(replicator: self).execute ::Geo::BlobDownloadService.new(replicator: self).execute
end end
......
# frozen_string_literal: true
module Geo
module VerifiableReplicator
extend ActiveSupport::Concern
include Delay
def after_verifiable_update
schedule_checksum_calculation if needs_checksum?
end
def calculate_checksum!
checksum = model_record.calculate_checksum!
update_verification_state!(checksum: checksum)
rescue => e
log_error('Error calculating the checksum', e)
update_verification_state!(failure: e.message)
end
# Check if given checksum matches known one
#
# @param [String] checksum
# @return [Boolean] whether checksum matches
def matches_checksum?(checksum)
model_record.verification_checksum == checksum
end
private
# Update checksum on Geo primary database
#
# @param [String] checksum value generated by the checksum routine
# @param [String] failure (optional) stacktrace from failed execution
def update_verification_state!(checksum: nil, failure: nil)
retry_at, retry_count = calculate_next_retry_attempt if failure.present?
model_record.update!(
verification_checksum: checksum,
verified_at: Time.current,
verification_failure: failure,
verification_retry_at: retry_at,
verification_retry_count: retry_count
)
end
def calculate_next_retry_attempt
retry_count = model_record.verification_retry_count.to_i + 1
[next_retry_time(retry_count), retry_count]
end
end
end
...@@ -19,6 +19,7 @@ RSpec.shared_examples 'a blob replicator' do ...@@ -19,6 +19,7 @@ RSpec.shared_examples 'a blob replicator' do
end end
it_behaves_like 'a replicator' it_behaves_like 'a replicator'
it_behaves_like 'a verifiable replicator'
# This could be included in each model's spec, but including it here is DRYer. # This could be included in each model's spec, but including it here is DRYer.
include_examples 'a replicable model' include_examples 'a replicable model'
...@@ -33,9 +34,8 @@ RSpec.shared_examples 'a blob replicator' do ...@@ -33,9 +34,8 @@ RSpec.shared_examples 'a blob replicator' do
"replicable_name" => replicator.replicable_name, "event_name" => "created", "payload" => { "model_record_id" => replicator.model_record.id }) "replicable_name" => replicator.replicable_name, "event_name" => "created", "payload" => { "model_record_id" => replicator.model_record.id })
end end
it 'schedules the checksum calculation if needed' do it 'calls #after_verifiable_update' do
expect(Geo::BlobVerificationPrimaryWorker).to receive(:perform_async) expect(replicator).to receive(:after_verifiable_update)
expect(replicator).to receive(:needs_checksum?).and_return(true)
replicator.handle_after_create_commit replicator.handle_after_create_commit
end end
...@@ -45,8 +45,8 @@ RSpec.shared_examples 'a blob replicator' do ...@@ -45,8 +45,8 @@ RSpec.shared_examples 'a blob replicator' do
stub_feature_flags(replicator.replication_enabled_feature_key => false) stub_feature_flags(replicator.replication_enabled_feature_key => false)
end end
it 'does not schedule the checksum calculation' do it 'does not call #after_verifiable_update' do
expect(Geo::BlobVerificationPrimaryWorker).not_to receive(:perform_async) expect(replicator).not_to receive(:after_verifiable_update)
replicator.handle_after_create_commit replicator.handle_after_create_commit
end end
...@@ -82,30 +82,6 @@ RSpec.shared_examples 'a blob replicator' do ...@@ -82,30 +82,6 @@ RSpec.shared_examples 'a blob replicator' do
end end
end end
describe '#calculate_checksum!' do
it 'calculates the checksum' do
model_record.save!
replicator.calculate_checksum!
expect(model_record.reload.verification_checksum).not_to be_nil
expect(model_record.reload.verified_at).not_to be_nil
end
it 'saves the error message and increments retry counter' do
model_record.save!
allow(model_record).to receive(:calculate_checksum!) do
raise StandardError.new('Failure to calculate checksum')
end
replicator.calculate_checksum!
expect(model_record.reload.verification_failure).to eq 'Failure to calculate checksum'
expect(model_record.verification_retry_count).to be 1
end
end
describe 'created event consumption' do describe 'created event consumption' do
context "when the blob's project is in replicables for this geo node" do context "when the blob's project is in replicables for this geo node" do
it 'invokes Geo::BlobDownloadService' do it 'invokes Geo::BlobDownloadService' do
......
# frozen_string_literal: true
# This is included by BlobReplicatorStrategy and RepositoryReplicatorStrategy.
#
RSpec.shared_examples 'a verifiable replicator' do
include EE::GeoHelpers
describe '#after_verifiable_update' do
it 'schedules the checksum calculation if needed' do
expect(replicator).to receive(:schedule_checksum_calculation)
expect(replicator).to receive(:needs_checksum?).and_return(true)
replicator.after_verifiable_update
end
end
describe '#calculate_checksum!' do
it 'calculates the checksum' do
model_record.save!
replicator.calculate_checksum!
expect(model_record.reload.verification_checksum).not_to be_nil
expect(model_record.reload.verified_at).not_to be_nil
end
it 'saves the error message and increments retry counter' do
model_record.save!
allow(model_record).to receive(:calculate_checksum!) do
raise StandardError.new('Failure to calculate checksum')
end
replicator.calculate_checksum!
expect(model_record.reload.verification_failure).to eq 'Failure to calculate checksum'
expect(model_record.verification_retry_count).to be 1
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment