Commit 01906f69 authored by Allison Browne's avatar Allison Browne Committed by Luke Duncalfe

Add configuration to pull mirroring limit

Add a new column pull_mirror_interval_seconds
which allows an adming to set the pull mirror interval
in seconds per instance.
parent 9b00092e
---
title: Improve CI for external repo with configurable maximum mirroring frequency
on self-hosted
merge_request: 48955
author:
type: changed
# frozen_string_literal: true
class AddPullMirrorIntervalToPlanLimits < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column :plan_limits, :pull_mirror_interval_seconds, :integer, default: 300, null: false
end
end
a3dd8cfe4a5d83ca370cac90acf127facf40c0fd63ae8d1d3f99418295bae148
\ No newline at end of file
...@@ -14987,7 +14987,8 @@ CREATE TABLE plan_limits ( ...@@ -14987,7 +14987,8 @@ CREATE TABLE plan_limits (
debian_max_file_size bigint DEFAULT '3221225472'::bigint NOT NULL, debian_max_file_size bigint DEFAULT '3221225472'::bigint NOT NULL,
project_feature_flags integer DEFAULT 200 NOT NULL, project_feature_flags integer DEFAULT 200 NOT NULL,
ci_max_artifact_size_api_fuzzing integer DEFAULT 0 NOT NULL, ci_max_artifact_size_api_fuzzing integer DEFAULT 0 NOT NULL,
ci_pipeline_deployments integer DEFAULT 500 NOT NULL ci_pipeline_deployments integer DEFAULT 500 NOT NULL,
pull_mirror_interval_seconds integer DEFAULT 300 NOT NULL
); );
CREATE SEQUENCE plan_limits_id_seq CREATE SEQUENCE plan_limits_id_seq
......
...@@ -181,6 +181,23 @@ Plan.default.actual_limits.update!(group_hooks: 100) ...@@ -181,6 +181,23 @@ Plan.default.actual_limits.update!(group_hooks: 100)
Set the limit to `0` to disable it. Set the limit to `0` to disable it.
## Pull Mirroring Interval
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/237891) in GitLab 13.7.
The [minimum time between pull refreshes](../user/project/repository/repository_mirroring.md)
defaults to 300 seconds (5 minutes).
To change this limit on a self-managed installation, run the following in the
[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
# If limits don't exist for the default plan, you can create one with:
# Plan.default.create_limits!
Plan.default.actual_limits.update!(pull_mirror_interval_seconds: 200)
```
## Incoming emails from auto-responders ## Incoming emails from auto-responders
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30327) in GitLab 12.4. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30327) in GitLab 12.4.
......
...@@ -11,8 +11,7 @@ Repository mirroring allows for mirroring of repositories to and from external s ...@@ -11,8 +11,7 @@ Repository mirroring allows for mirroring of repositories to and from external s
used to mirror branches, tags, and commits between repositories. used to mirror branches, tags, and commits between repositories.
A repository mirror at GitLab will be updated automatically. You can also manually trigger an update A repository mirror at GitLab will be updated automatically. You can also manually trigger an update
at most once every 5 minutes. Follow [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/237891) at most once every 5 minutes on GitLab.com with [the limit set by the administrator on self-managed instances](../../../administration/instance_limits.md#pull-mirroring-interval).
for discussions on how to potentially reduce the delay.
## Overview ## Overview
...@@ -30,7 +29,7 @@ Users with at least [Developer access](../../permissions.md) to the project can ...@@ -30,7 +29,7 @@ Users with at least [Developer access](../../permissions.md) to the project can
immediate update, unless: immediate update, unless:
- The mirror is already being updated. - The mirror is already being updated.
- 5 minutes haven't elapsed since its last update. - The [limit for pull mirroring interval seconds](../../../administration/instance_limits.md#pull-mirroring-interval) has not elapsed since its last update.
For security reasons, in [GitLab 12.10 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27166), For security reasons, in [GitLab 12.10 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27166),
the URL to the original repository is only displayed to users with the URL to the original repository is only displayed to users with
......
# frozen_string_literal: true # frozen_string_literal: true
class StartPullMirroringService < BaseService class StartPullMirroringService < BaseService
INTERVAL = 5.minutes
def execute def execute
import_state = project.import_state import_state = project.import_state
...@@ -12,7 +10,7 @@ class StartPullMirroringService < BaseService ...@@ -12,7 +10,7 @@ class StartPullMirroringService < BaseService
import_state.force_import_job! import_state.force_import_job!
else else
import_state.reset_retry_count if import_state.hard_failed? import_state.reset_retry_count if import_state.hard_failed?
import_state.update(next_execution_timestamp: INTERVAL.since(import_state.last_update_at)) import_state.update(next_execution_timestamp: interval.since(import_state.last_update_at))
end end
success success
...@@ -20,9 +18,13 @@ class StartPullMirroringService < BaseService ...@@ -20,9 +18,13 @@ class StartPullMirroringService < BaseService
private private
def interval
@interval ||= project.actual_limits.pull_mirror_interval_seconds.seconds
end
def update_now?(import_state) def update_now?(import_state)
import_state.last_successful_update_at.nil? || import_state.last_successful_update_at.nil? ||
import_state.last_update_at.nil? || import_state.last_update_at.nil? ||
import_state.last_update_at < INTERVAL.ago import_state.last_update_at < interval.ago
end end
end end
...@@ -29,33 +29,47 @@ RSpec.describe StartPullMirroringService do ...@@ -29,33 +29,47 @@ RSpec.describe StartPullMirroringService do
it_behaves_like 'force mirror update' it_behaves_like 'force mirror update'
context 'when project mirror has been updated in the last 5 minutes' do shared_examples 'mirrors using interval' do |interval_minutes:|
it 'schedules next execution' do context 'when project mirror has been updated in the interval' do
travel_to(Time.current) do it 'schedules next execution' do
import_state.update(last_update_at: 3.minutes.ago, last_successful_update_at: 10.minutes.ago) freeze_time do
import_state.update(last_update_at: (interval_minutes - 1).minutes.ago, last_successful_update_at: 10.minutes.ago)
expect { execute }
.to change { import_state.next_execution_timestamp }
.to(interval_minutes.minutes.since(import_state.last_update_at))
.and not_change { UpdateAllMirrorsWorker.jobs.size }
end
end
end
expect { execute } context 'when project mirror has been updated outside of the interval' do
.to change { import_state.next_execution_timestamp } before do
.to(2.minutes.from_now) import_state.update(last_update_at: (interval_minutes + 1).minutes.ago, last_successful_update_at: 10.minutes.ago)
.and not_change { UpdateAllMirrorsWorker.jobs.size }
end end
it_behaves_like 'force mirror update'
end end
end
context 'when project mirror has been updated more than 5 minutes ago' do context 'when project mirror has been updated in interval but has never been successfully updated' do
before do before do
import_state.update(last_update_at: 6.minutes.ago, last_successful_update_at: 10.minutes.ago) import_state.update(last_update_at: (interval_minutes - 1).minutes.ago, last_successful_update_at: nil)
end
it_behaves_like 'force mirror update'
end end
end
it_behaves_like 'force mirror update' context 'with default interval' do
it_behaves_like 'mirrors using interval', interval_minutes: 5
end end
context 'when project mirror has been updated in the last 5 minutes but has never been successfully updated' do context 'with a custom interval' do
before do before do
import_state.update(last_update_at: 3.minutes.ago, last_successful_update_at: nil) Plan.default.actual_limits.update!(pull_mirror_interval_seconds: 2.minutes)
end end
it_behaves_like 'force mirror update' it_behaves_like 'mirrors using interval', interval_minutes: 2
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