Check which repositories should be synced

parent b5578fb5
...@@ -12,8 +12,8 @@ module Geo ...@@ -12,8 +12,8 @@ module Geo
def execute def execute
try_obtain_lease do try_obtain_lease do
log('Started repository sync') log('Started repository sync')
started_at, finished_at = fetch_repositories sync_project_repository
update_registry(started_at, finished_at) sync_wiki_repository
log('Finished repository sync') log('Finished repository sync')
end end
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
...@@ -26,14 +26,51 @@ module Geo ...@@ -26,14 +26,51 @@ module Geo
@project ||= Project.find(project_id) @project ||= Project.find(project_id)
end end
def fetch_repositories def registry
@registry ||= Geo::ProjectRegistry.find_or_initialize_by(project_id: project_id)
end
def sync_project_repository
return unless sync_repository?
started_at, finished_at = fetch_project_repository
update_registry(:repository, started_at, finished_at)
expire_repository_caches
end
def sync_repository?
return true if registry.resync_repository?
return true if registry.last_repository_successful_sync_at.nil?
return true if registry.last_repository_synced_at.nil?
false
end
def sync_wiki_repository
return unless sync_wiki?
started_at, finished_at = fetch_wiki_repository
update_registry(:wiki, started_at, finished_at)
end
def sync_wiki?
return true if registry.resync_wiki?
return true if registry.last_wiki_successful_sync_at.nil?
return true if registry.last_wiki_synced_at.nil?
false
end
def fetch_project_repository
return unless sync_repository?
log('Fetching project repository')
started_at = DateTime.now started_at = DateTime.now
finished_at = nil finished_at = nil
begin begin
fetch_project_repository project.create_repository unless project.repository_exists?
fetch_wiki_repository project.repository.fetch_geo_mirror(ssh_url_to_repo)
expire_repository_caches
finished_at = DateTime.now finished_at = DateTime.now
rescue Gitlab::Shell::Error => e rescue Gitlab::Shell::Error => e
...@@ -47,18 +84,25 @@ module Geo ...@@ -47,18 +84,25 @@ module Geo
[started_at, finished_at] [started_at, finished_at]
end end
def fetch_project_repository
log('Fetching project repository')
project.create_repository unless project.repository_exists?
project.repository.fetch_geo_mirror(ssh_url_to_repo)
end
def fetch_wiki_repository def fetch_wiki_repository
# Second .wiki call returns a Gollum::Wiki, and it will always create the physical repository when not found return unless sync_wiki?
if project.wiki.wiki.exist?
log('Fetching wiki repository') log('Fetching wiki repository')
project.wiki.repository.fetch_geo_mirror(ssh_url_to_wiki) started_at = DateTime.now
finished_at = nil
begin
# Second .wiki call returns a Gollum::Wiki, and it will always create the physical repository when not found
if project.wiki.wiki.exist?
project.wiki.repository.fetch_geo_mirror(ssh_url_to_wiki)
end
finished_at = DateTime.now
rescue Gitlab::Shell::Error => e
Rails.logger.error("#{self.class.name}: Error syncing wiki repository for project #{project.path_with_namespace}: #{e}")
end end
[started_at, finished_at]
end end
def expire_repository_caches def expire_repository_caches
...@@ -84,11 +128,15 @@ module Geo ...@@ -84,11 +128,15 @@ module Geo
Gitlab::ExclusiveLease.cancel(lease_key, repository_lease) Gitlab::ExclusiveLease.cancel(lease_key, repository_lease)
end end
def update_registry(started_at, finished_at) def update_registry(type, started_at, finished_at)
log('Updating repository sync information') log('Updating #{type} sync information')
registry = Geo::ProjectRegistry.find_or_initialize_by(project_id: project_id) registry.public_send("last_#{type}_synced_at=", started_at)
registry.last_repository_synced_at = started_at
registry.last_repository_successful_sync_at = finished_at if finished_at if finished_at
registry.public_send("last_#{type}_successful_sync_at=", started_at)
registry.public_send("resync_#{type}=", false)
end
registry.save registry.save
end end
......
...@@ -16,7 +16,7 @@ describe Geo::RepositorySyncService, services: true do ...@@ -16,7 +16,7 @@ describe Geo::RepositorySyncService, services: true do
end end
describe '#execute' do describe '#execute' do
context 'when repository is empty' do context 'when project have never been synced' do
let(:project) { create(:project_empty_repo) } let(:project) { create(:project_empty_repo) }
it 'fetches project repositories' do it 'fetches project repositories' do
...@@ -55,11 +55,11 @@ describe Geo::RepositorySyncService, services: true do ...@@ -55,11 +55,11 @@ describe Geo::RepositorySyncService, services: true do
end end
context 'tracking database' do context 'tracking database' do
it 'tracks repository sync' do it 'create a new registry' do
expect { subject.execute }.to change(Geo::ProjectRegistry, :count).by(1) expect { subject.execute }.to change(Geo::ProjectRegistry, :count).by(1)
end end
it 'stores last_repository_successful_sync_at when succeed' do it 'sets last_repository_successful_sync_at when repository sync succeed' do
subject.execute subject.execute
registry = Geo::ProjectRegistry.find_by(project_id: project.id) registry = Geo::ProjectRegistry.find_by(project_id: project.id)
...@@ -67,8 +67,8 @@ describe Geo::RepositorySyncService, services: true do ...@@ -67,8 +67,8 @@ describe Geo::RepositorySyncService, services: true do
expect(registry.last_repository_successful_sync_at).not_to be_nil expect(registry.last_repository_successful_sync_at).not_to be_nil
end end
it 'reset last_repository_successful_sync_at when fail' do it 'resets last_repository_successful_sync_at when repository sync fail' do
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) { raise Gitlab::Shell::Error } allow_any_instance_of(Repository).to receive(:fetch_geo_mirror).with(/#{project.path_with_namespace}\.git/) { raise Gitlab::Shell::Error }
subject.execute subject.execute
...@@ -76,58 +76,87 @@ describe Geo::RepositorySyncService, services: true do ...@@ -76,58 +76,87 @@ describe Geo::RepositorySyncService, services: true do
expect(registry.last_repository_successful_sync_at).to be_nil expect(registry.last_repository_successful_sync_at).to be_nil
end end
it 'sets last_wiki_successful_sync_at when wiki sync succeed' do
subject.execute
registry = Geo::ProjectRegistry.find_by(project_id: project.id)
expect(registry.last_wiki_successful_sync_at).not_to be_nil
end
it 'resets last_wiki_successful_sync_at when wiki sync fail' do
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror).with(/#{project.path_with_namespace}\.wiki.git/) { raise Gitlab::Shell::Error }
subject.execute
registry = Geo::ProjectRegistry.find_by(project_id: project.id)
expect(registry.last_wiki_successful_sync_at).to be_nil
end
end end
end end
context 'when repository exists and is not empty' do context 'when project have been synced' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:last_repository_synced_at) { 5.days.ago }
let(:last_wiki_synced_at) { 4.days.ago }
it 'fetches project repositories' do let!(:registry) do
fetch_count = 0 Geo::ProjectRegistry.create(
project: project,
last_repository_synced_at: last_repository_synced_at,
last_repository_successful_sync_at: last_repository_synced_at,
last_wiki_synced_at: last_wiki_synced_at,
last_wiki_successful_sync_at: last_wiki_synced_at,
resync_repository: false,
resync_wiki: false
)
end
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) do it 'does not fetch project repositories' do
fetch_count += 1 expect_any_instance_of(Repository).not_to receive(:fetch_geo_mirror)
end
subject.execute subject.execute
expect(fetch_count).to eq 2
end end
context 'tracking database' do context 'tracking database' do
it 'tracks repository sync' do it 'does not create a new registry' do
expect { subject.execute }.to change(Geo::ProjectRegistry, :count).by(1) expect { subject.execute }.not_to change(Geo::ProjectRegistry, :count)
end end
it 'stores last_repository_successful_sync_at when succeed' do it 'does not update last_repository_successful_sync_at' do
subject.execute subject.execute
registry = Geo::ProjectRegistry.find_by(project_id: project.id) registry.reload
expect(registry.last_repository_successful_sync_at).not_to be_nil expect(registry.last_repository_synced_at).to eq last_repository_synced_at
expect(registry.last_repository_successful_sync_at).to eq last_repository_synced_at
end end
it 'reset last_repository_successful_sync_at when fail' do it 'does not update last_wiki_successful_sync_at' do
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) { raise Gitlab::Shell::Error }
subject.execute subject.execute
registry = Geo::ProjectRegistry.find_by(project_id: project.id) registry.reload
expect(registry.last_repository_successful_sync_at).to be_nil expect(registry.last_wiki_synced_at).to eq last_wiki_synced_at
expect(registry.last_wiki_successful_sync_at).to eq last_wiki_synced_at
end end
end end
end end
context 'when repository was synced successfully' do context 'when last attempt to sync project repositories failed' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:last_repository_synced_at) { 5.days.ago }
let!(:registry) do let!(:registry) do
Geo::ProjectRegistry.create( Geo::ProjectRegistry.create(
project: project, project: project,
last_repository_synced_at: last_repository_synced_at, last_repository_synced_at: DateTime.now,
last_repository_successful_sync_at: last_repository_synced_at last_repository_successful_sync_at: nil,
last_wiki_synced_at: DateTime.now,
last_wiki_successful_sync_at: nil,
resync_repository: false,
resync_wiki: false
) )
end end
...@@ -144,11 +173,49 @@ describe Geo::RepositorySyncService, services: true do ...@@ -144,11 +173,49 @@ describe Geo::RepositorySyncService, services: true do
end end
context 'tracking database' do context 'tracking database' do
it 'does not create a new registry' do it 'sets last_repository_successful_sync_at' do
expect { subject.execute }.not_to change(Geo::ProjectRegistry, :count) subject.execute
registry.reload
expect(registry.last_repository_successful_sync_at).not_to be_nil
end
it 'sets last_wiki_successful_sync_at' do
subject.execute
registry.reload
expect(registry.last_wiki_successful_sync_at).not_to be_nil
end end
end
end
context 'when project repository is dirty' do
let(:project) { create(:project) }
let(:last_repository_synced_at) { 5.days.ago }
let(:last_wiki_synced_at) { 4.days.ago }
let!(:registry) do
Geo::ProjectRegistry.create(
project: project,
last_repository_synced_at: last_repository_synced_at,
last_repository_successful_sync_at: last_repository_synced_at,
last_wiki_synced_at: last_wiki_synced_at,
last_wiki_successful_sync_at: last_wiki_synced_at,
resync_repository: true,
resync_wiki: false
)
end
it 'fetches project repository' do
expect_any_instance_of(Repository).to receive(:fetch_geo_mirror).once
it 'updates registry when succeed' do subject.execute
end
context 'tracking database' do
it 'updates last_repository_successful_sync_at' do
subject.execute subject.execute
registry.reload registry.reload
...@@ -157,51 +224,73 @@ describe Geo::RepositorySyncService, services: true do ...@@ -157,51 +224,73 @@ describe Geo::RepositorySyncService, services: true do
expect(registry.last_repository_successful_sync_at).to be_within(1.minute).of(Time.now) expect(registry.last_repository_successful_sync_at).to be_within(1.minute).of(Time.now)
end end
it 'does not update registry last_repository_successful_sync_at when fail' do it 'does not update last_wiki_successful_sync_at' do
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) { raise Gitlab::Shell::Error } subject.execute
registry.reload
expect(registry.last_wiki_synced_at).to eq last_wiki_synced_at
expect(registry.last_wiki_successful_sync_at).to eq last_wiki_synced_at
end
it 'resets resync_repository' do
subject.execute subject.execute
registry.reload registry.reload
expect(registry.last_repository_synced_at).to be_within(1.minute).of(Time.now) expect(registry.resync_repository).to be false
expect(registry.last_repository_successful_sync_at).to be_within(1.minute).of(last_repository_synced_at)
end end
end end
end end
context 'when last attempt to sync the repository failed' do context 'when project wiki is dirty' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:last_repository_synced_at) { 5.days.ago }
let(:last_wiki_synced_at) { 4.days.ago }
let!(:registry) do let!(:registry) do
Geo::ProjectRegistry.create( Geo::ProjectRegistry.create(
project: project, project: project,
last_repository_synced_at: DateTime.now, last_repository_synced_at: last_repository_synced_at,
last_repository_successful_sync_at: nil last_repository_successful_sync_at: last_repository_synced_at,
last_wiki_synced_at: last_wiki_synced_at,
last_wiki_successful_sync_at: last_wiki_synced_at,
resync_repository: false,
resync_wiki: true
) )
end end
it 'fetches project repositories' do it 'fetches wiki repository' do
fetch_count = 0 expect_any_instance_of(Repository).to receive(:fetch_geo_mirror).once
allow_any_instance_of(Repository).to receive(:fetch_geo_mirror) do
fetch_count += 1
end
subject.execute subject.execute
expect(fetch_count).to eq 2
end end
context 'tracking database' do context 'tracking database' do
it 'does not create a new registry' do it 'updates last_wiki_successful_sync_at' do
expect { subject.execute }.not_to change(Geo::ProjectRegistry, :count) subject.execute
registry.reload
expect(registry.last_wiki_synced_at).to be_within(1.minute).of(Time.now)
expect(registry.last_wiki_successful_sync_at).to be_within(1.minute).of(Time.now)
end end
it 'updates last_repository_successful_sync_at' do it 'does not update last_repository_successful_sync_at' do
subject.execute subject.execute
expect(registry.reload.last_repository_successful_sync_at).not_to be_nil registry.reload
expect(registry.last_repository_synced_at).to eq last_repository_synced_at
expect(registry.last_repository_successful_sync_at).to eq last_repository_synced_at
end
it 'resets resync_wiki' do
subject.execute
registry.reload
expect(registry.resync_wiki).to be false
end end
end 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