Commit 67e51e9c authored by Robert Speicher's avatar Robert Speicher

Merge branch 'fix/geo-backfill-worker' into 'master'

Populate the tracking DB for projects synced before upgrade to 9.0

See merge request !1437
parents 945c9f7f 114da7cc
...@@ -10,6 +10,8 @@ module Geo ...@@ -10,6 +10,8 @@ module Geo
end end
def execute def execute
return if backfilled?(project)
try_obtain_lease do try_obtain_lease do
log('Started repository sync') log('Started repository sync')
started_at, finished_at = fetch_repositories started_at, finished_at = fetch_repositories
...@@ -81,6 +83,29 @@ module Geo ...@@ -81,6 +83,29 @@ module Geo
Gitlab::ExclusiveLease.cancel(lease_key, repository_lease) Gitlab::ExclusiveLease.cancel(lease_key, repository_lease)
end end
def backfilled?(project)
return false unless project.repository.exists?
return false if project.repository.exists? && project.repository.empty?
return true if registry_exists?(project)
# When Geo customers upgrade to 9.0, the secondaries nodes that are
# enabled will start the backfilling process automatically. We need
# to populate the tracking database correctly for projects synced
# before the process being started or projects created during the
# backfilling. Otherwise, the query to retrieve the projects will
# always return the same projects because they don't have entries
# in the tracking database
update_registry(DateTime.now, DateTime.now)
true
end
def registry_exists?(project)
Geo::ProjectRegistry.where(project_id: project.id)
.where.not(last_repository_synced_at: nil)
.any?
end
def update_registry(started_at, finished_at) def update_registry(started_at, finished_at)
log('Updating registry information') log('Updating registry information')
registry = Geo::ProjectRegistry.find_or_initialize_by(project_id: project.id) registry = Geo::ProjectRegistry.find_or_initialize_by(project_id: project.id)
......
...@@ -19,9 +19,6 @@ class GeoBackfillWorker ...@@ -19,9 +19,6 @@ class GeoBackfillWorker
break if over_time?(start_time) break if over_time?(start_time)
break unless Gitlab::Geo.current_node_enabled? break unless Gitlab::Geo.current_node_enabled?
project = Project.find(project_id)
next if synced?(project)
# We try to obtain a lease here for the entire backfilling process # We try to obtain a lease here for the entire backfilling process
# because backfill the repositories continuously at a controlled rate # because backfill the repositories continuously at a controlled rate
# instead of hammering the primary node. Initially, we are backfilling # instead of hammering the primary node. Initially, we are backfilling
...@@ -51,16 +48,6 @@ class GeoBackfillWorker ...@@ -51,16 +48,6 @@ class GeoBackfillWorker
Time.now - start_time >= RUN_TIME Time.now - start_time >= RUN_TIME
end end
def synced?(project)
project.repository_exists? || registry_exists?(project)
end
def registry_exists?(project)
Geo::ProjectRegistry.where(project_id: project.id)
.where.not(last_repository_synced_at: nil)
.any?
end
def try_obtain_lease def try_obtain_lease
lease = Gitlab::ExclusiveLease.new(lease_key, timeout: lease_timeout).try_obtain lease = Gitlab::ExclusiveLease.new(lease_key, timeout: lease_timeout).try_obtain
......
...@@ -2,62 +2,117 @@ require 'spec_helper' ...@@ -2,62 +2,117 @@ require 'spec_helper'
describe Geo::RepositoryBackfillService, services: true do describe Geo::RepositoryBackfillService, services: true do
let!(:primary) { create(:geo_node, :primary, host: 'primary-geo-node') } let!(:primary) { create(:geo_node, :primary, host: 'primary-geo-node') }
let(:project) { create(:empty_project) }
subject { described_class.new(project.id) } subject { described_class.new(project.id) }
describe '#execute' do describe '#execute' do
it 'fetches project repositories' do context 'when repository is empty' do
fetch_count = 0 let(:project) { create(:project_empty_repo) }
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) do it 'fetches project repositories' do
fetch_count += 1 fetch_count = 0
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) do
fetch_count += 1
end
subject.execute
expect(fetch_count).to eq 2
end end
subject.execute it 'expires repository caches' do
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) { true }
expect(fetch_count).to eq 2 expect_any_instance_of(Repository).to receive(:expire_all_method_caches).once
end expect_any_instance_of(Repository).to receive(:expire_branch_cache).once
expect_any_instance_of(Repository).to receive(:expire_content_cache).once
it 'expires repository caches' do subject.execute
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) { true } end
expect_any_instance_of(Repository).to receive(:expire_all_method_caches).once it 'releases lease' do
expect_any_instance_of(Repository).to receive(:expire_branch_cache).once expect(Gitlab::ExclusiveLease).to receive(:cancel).once.and_call_original
expect_any_instance_of(Repository).to receive(:expire_content_cache).once
subject.execute subject.execute
end end
it 'releases lease' do context 'tracking database' do
expect(Gitlab::ExclusiveLease).to receive(:cancel).once.and_call_original it 'tracks repository sync' do
expect { subject.execute }.to change(Geo::ProjectRegistry, :count).by(1)
end
subject.execute it 'stores last_repository_successful_sync_at when succeed' do
end allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) { true }
subject.execute
registry = Geo::ProjectRegistry.find_by(project_id: project.id)
expect(registry.last_repository_successful_sync_at).not_to be_nil
end
context 'tracking database' do it 'reset last_repository_successful_sync_at when fail' do
it 'tracks repository sync' do allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) { raise Gitlab::Shell::Error }
expect { subject.execute }.to change(Geo::ProjectRegistry, :count).by(1)
subject.execute
registry = Geo::ProjectRegistry.find_by(project_id: project.id)
expect(registry.last_repository_successful_sync_at).to be_nil
end
end end
end
it 'stores last_repository_successful_sync_at when succeed' do context 'when repository exists and is not empty' do
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) { true } let(:project) { create(:project) }
it 'does not fetch the project repositories' do
fetch_count = 0
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) do
fetch_count += 1
end
subject.execute subject.execute
registry = Geo::ProjectRegistry.find_by(project_id: project.id) expect(fetch_count).to eq 0
end
expect(registry.last_repository_successful_sync_at).not_to be_nil context 'tracking database' do
it 'tracks missing repository sync' do
expect { subject.execute }.to change(Geo::ProjectRegistry, :count).by(1)
end
end end
end
it 'reset last_repository_successful_sync_at when fail' do context 'when repository was backfilled' do
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) { raise Gitlab::Shell::Error } let(:project) { create(:project) }
let!(:registry) do
Geo::ProjectRegistry.create(
project: project,
last_repository_synced_at: DateTime.now,
last_repository_successful_sync_at: DateTime.now
)
end
it 'does not fetch the project repositories' do
fetch_count = 0
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) do
fetch_count += 1
end
subject.execute subject.execute
registry = Geo::ProjectRegistry.find_by(project_id: project.id) expect(fetch_count).to eq 0
end
expect(registry.last_repository_successful_sync_at).to be_nil context 'tracking database' do
it 'does not track repository sync' do
expect { subject.execute }.not_to change(Geo::ProjectRegistry, :count)
end
end end
end end
end end
......
...@@ -42,14 +42,6 @@ describe Geo::GeoBackfillWorker, services: true do ...@@ -42,14 +42,6 @@ describe Geo::GeoBackfillWorker, services: true do
subject.perform subject.perform
end end
it 'does not perform Geo::RepositoryBackfillService for projects that repository exists' do
create_list(:project, 2)
expect(Geo::RepositoryBackfillService).to receive(:new).twice.and_return(spy)
subject.perform
end
it 'does not perform Geo::RepositoryBackfillService when can not obtain a lease' do it 'does not perform Geo::RepositoryBackfillService when can not obtain a lease' do
allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { false } allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { false }
......
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