Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
ef7fa8ed
Commit
ef7fa8ed
authored
Aug 14, 2017
by
Tiago Botelho
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improves handling of the mirror threshold
parent
95ead8b1
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
115 additions
and
58 deletions
+115
-58
app/workers/repository_update_mirror_worker.rb
app/workers/repository_update_mirror_worker.rb
+10
-1
app/workers/update_all_mirrors_worker.rb
app/workers/update_all_mirrors_worker.rb
+1
-6
changelogs/unreleased-ee/3134-improve-mirror-threshold-handling.yml
.../unreleased-ee/3134-improve-mirror-threshold-handling.yml
+4
-0
ee/app/models/ee/project.rb
ee/app/models/ee/project.rb
+1
-0
lib/gitlab/mirror.rb
lib/gitlab/mirror.rb
+10
-2
spec/lib/gitlab/mirror_spec.rb
spec/lib/gitlab/mirror_spec.rb
+43
-9
spec/workers/repository_update_mirror_worker_spec.rb
spec/workers/repository_update_mirror_worker_spec.rb
+46
-40
No files found.
app/workers/repository_update_mirror_worker.rb
View file @
ef7fa8ed
...
@@ -5,6 +5,9 @@ class RepositoryUpdateMirrorWorker
...
@@ -5,6 +5,9 @@ class RepositoryUpdateMirrorWorker
include
Gitlab
::
ShellAdapter
include
Gitlab
::
ShellAdapter
include
DedicatedSidekiqQueue
include
DedicatedSidekiqQueue
LEASE_KEY
=
'repository_update_mirror_worker_start_scheduler'
.
freeze
LEASE_TIMEOUT
=
2
.
seconds
# Retry not neccessary. It will try again at the next update interval.
# Retry not neccessary. It will try again at the next update interval.
sidekiq_options
retry:
false
,
status_expiration:
StuckImportJobsWorker
::
IMPORT_JOBS_EXPIRATION
sidekiq_options
retry:
false
,
status_expiration:
StuckImportJobsWorker
::
IMPORT_JOBS_EXPIRATION
...
@@ -30,11 +33,17 @@ class RepositoryUpdateMirrorWorker
...
@@ -30,11 +33,17 @@ class RepositoryUpdateMirrorWorker
fail_mirror
(
project
,
ex
.
message
)
fail_mirror
(
project
,
ex
.
message
)
raise
UpdateError
,
"
#{
ex
.
class
}
:
#{
ex
.
message
}
"
raise
UpdateError
,
"
#{
ex
.
class
}
:
#{
ex
.
message
}
"
ensure
ensure
UpdateAllMirrorsWorker
.
perform_async
if
Gitlab
::
Mirror
.
threshold_reached?
if
!
lease
.
exists?
&&
Gitlab
::
Mirror
.
reschedule_immediately?
&&
lease
.
try_obtain
UpdateAllMirrorsWorker
.
perform_async
end
end
end
private
private
def
lease
@lease
||=
::
Gitlab
::
ExclusiveLease
.
new
(
LEASE_KEY
,
timeout:
LEASE_TIMEOUT
)
end
def
start_mirror
(
project
)
def
start_mirror
(
project
)
if
project
.
import_start
if
project
.
import_start
Gitlab
::
Mirror
.
increment_metric
(
:mirrors_running
,
'Mirrors running count'
)
Gitlab
::
Mirror
.
increment_metric
(
:mirrors_running
,
'Mirrors running count'
)
...
...
app/workers/update_all_mirrors_worker.rb
View file @
ef7fa8ed
...
@@ -51,12 +51,7 @@ class UpdateAllMirrorsWorker
...
@@ -51,12 +51,7 @@ class UpdateAllMirrorsWorker
end
end
def
pull_mirrors_batch
(
freeze_at
:,
batch_size
:,
offset_at:
nil
)
def
pull_mirrors_batch
(
freeze_at
:,
batch_size
:,
offset_at:
nil
)
relation
=
Project
relation
=
Project
.
mirrors_to_sync
(
freeze_at
).
reorder
(
'project_mirror_data.next_execution_timestamp'
).
limit
(
batch_size
)
.
mirror
.
joins
(
:mirror_data
)
.
where
(
"next_execution_timestamp <= ? AND import_status NOT IN ('scheduled', 'started')"
,
freeze_at
)
.
reorder
(
'project_mirror_data.next_execution_timestamp'
)
.
limit
(
batch_size
)
relation
=
relation
.
where
(
'next_execution_timestamp > ?'
,
offset_at
)
if
offset_at
relation
=
relation
.
where
(
'next_execution_timestamp > ?'
,
offset_at
)
if
offset_at
...
...
changelogs/unreleased-ee/3134-improve-mirror-threshold-handling.yml
0 → 100644
View file @
ef7fa8ed
---
title
:
Improves handling of the mirror threshold.
merge_request
:
2671
author
:
ee/app/models/ee/project.rb
View file @
ef7fa8ed
...
@@ -40,6 +40,7 @@ module EE
...
@@ -40,6 +40,7 @@ module EE
scope
:with_shared_runners_limit_enabled
,
->
{
with_shared_runners
.
non_public_only
}
scope
:with_shared_runners_limit_enabled
,
->
{
with_shared_runners
.
non_public_only
}
scope
:mirror
,
->
{
where
(
mirror:
true
)
}
scope
:mirror
,
->
{
where
(
mirror:
true
)
}
scope
:mirrors_to_sync
,
->
(
freeze_at
)
{
mirror
.
joins
(
:mirror_data
).
without_import_status
(
:scheduled
,
:started
).
where
(
"next_execution_timestamp <= ?"
,
freeze_at
)
}
scope
:with_remote_mirrors
,
->
{
joins
(
:remote_mirrors
).
where
(
remote_mirrors:
{
enabled:
true
}).
distinct
}
scope
:with_remote_mirrors
,
->
{
joins
(
:remote_mirrors
).
where
(
remote_mirrors:
{
enabled:
true
}).
distinct
}
scope
:with_wiki_enabled
,
->
{
with_feature_enabled
(
:wiki
)
}
scope
:with_wiki_enabled
,
->
{
with_feature_enabled
(
:wiki
)
}
...
...
lib/gitlab/mirror.rb
View file @
ef7fa8ed
...
@@ -24,8 +24,16 @@ module Gitlab
...
@@ -24,8 +24,16 @@ module Gitlab
available_capacity
<=
0
available_capacity
<=
0
end
end
def
threshold_reached?
def
reschedule_immediately?
available_capacity
>=
capacity_threshold
available_spots
=
available_capacity
return
false
if
available_spots
<
capacity_threshold
# Only reschedule if we are able to completely fill up the available spots.
mirrors_ready_to_sync_count
>=
available_spots
end
def
mirrors_ready_to_sync_count
Project
.
mirrors_to_sync
(
Time
.
now
).
count
end
end
def
available_capacity
def
available_capacity
...
...
spec/lib/gitlab/mirror_spec.rb
View file @
ef7fa8ed
...
@@ -64,25 +64,59 @@ describe Gitlab::Mirror do
...
@@ -64,25 +64,59 @@ describe Gitlab::Mirror do
end
end
end
end
describe
'#
threshold_reached
?'
do
describe
'#
reschedule_immediately
?'
do
let
(
:mirror_capacity_threshold
)
{
current_application_settings
.
mirror_capacity_threshold
}
let
(
:mirror_capacity_threshold
)
{
current_application_settings
.
mirror_capacity_threshold
}
context
'with number of mirrors to sync equal to the available capacity'
do
it
'returns true if available capacity surpassed defined threshold'
do
it
'returns true if available capacity surpassed defined threshold'
do
expect
(
described_class
).
to
receive
(
:available_capacity
).
and_return
(
mirror_capacity_threshold
+
1
)
available_capacity
=
mirror_capacity_threshold
+
1
expect
(
described_class
).
to
receive
(
:available_capacity
).
and_return
(
available_capacity
)
expect
(
described_class
).
to
receive
(
:mirrors_ready_to_sync_count
).
and_return
(
available_capacity
)
expect
(
described_class
.
threshold_reached
?
).
to
eq
(
true
)
expect
(
described_class
.
reschedule_immediately
?
).
to
eq
(
true
)
end
end
it
'returns true if available capacity is equal to the defined threshold'
do
it
'returns true if available capacity is equal to the defined threshold'
do
expect
(
described_class
).
to
receive
(
:available_capacity
).
and_return
(
mirror_capacity_threshold
)
expect
(
described_class
).
to
receive
(
:available_capacity
).
and_return
(
mirror_capacity_threshold
)
expect
(
described_class
).
to
receive
(
:mirrors_ready_to_sync_count
).
and_return
(
mirror_capacity_threshold
)
expect
(
described_class
.
reschedule_immediately?
).
to
eq
(
true
)
end
end
expect
(
described_class
.
threshold_reached?
).
to
eq
(
true
)
context
'with number of mirrors to sync surpassing the available capacity'
do
it
'returns true if available capacity surpassed defined threshold'
do
available_capacity
=
mirror_capacity_threshold
+
1
expect
(
described_class
).
to
receive
(
:available_capacity
).
and_return
(
available_capacity
)
expect
(
described_class
).
to
receive
(
:mirrors_ready_to_sync_count
).
and_return
(
available_capacity
+
1
)
expect
(
described_class
.
reschedule_immediately?
).
to
eq
(
true
)
end
it
'returns true if available capacity is equal to the defined threshold'
do
expect
(
described_class
).
to
receive
(
:available_capacity
).
and_return
(
mirror_capacity_threshold
)
expect
(
described_class
).
to
receive
(
:mirrors_ready_to_sync_count
).
and_return
(
mirror_capacity_threshold
+
1
)
expect
(
described_class
.
reschedule_immediately?
).
to
eq
(
true
)
end
end
it
'returns false if mirrors ready to sync is below the available capacity'
do
expect
(
described_class
).
to
receive
(
:available_capacity
).
and_return
(
mirror_capacity_threshold
+
1
)
expect
(
described_class
).
to
receive
(
:mirrors_ready_to_sync_count
).
and_return
(
mirror_capacity_threshold
)
expect
(
described_class
.
reschedule_immediately?
).
to
eq
(
false
)
end
end
it
'returns false if available capacity is below the defined threshold'
do
it
'returns false if available capacity is below the defined threshold'
do
expect
(
described_class
).
to
receive
(
:available_capacity
).
and_return
(
mirror_capacity_threshold
-
1
)
available_capacity
=
mirror_capacity_threshold
-
1
expect
(
described_class
).
to
receive
(
:available_capacity
).
and_return
(
available_capacity
)
expect
(
described_class
).
not_to
receive
(
:mirrors_ready_to_sync_count
)
expect
(
described_class
.
threshold_reached
?
).
to
eq
(
false
)
expect
(
described_class
.
reschedule_immediately
?
).
to
eq
(
false
)
end
end
after
do
after
do
...
...
spec/workers/repository_update_mirror_worker_spec.rb
View file @
ef7fa8ed
require
'rails_helper'
require
'rails_helper'
describe
RepositoryUpdateMirrorWorker
do
describe
RepositoryUpdateMirrorWorker
do
subject
{
described_class
.
new
}
describe
'#perform'
do
describe
'#perform'
do
context
'with status none'
do
let!
(
:project
)
{
create
(
:project
,
:mirror
,
:import_scheduled
)
}
let
(
:project
)
{
create
(
:project
,
:mirror
,
:import_scheduled
)
}
before
do
allow_any_instance_of
(
Gitlab
::
ExclusiveLease
).
to
receive
(
:try_obtain
).
and_return
(
true
)
end
it
'sets status as finished when update mirror service executes successfully'
do
it
'sets status as finished when update mirror service executes successfully'
do
expect_any_instance_of
(
Projects
::
UpdateMirrorService
).
to
receive
(
:execute
).
and_return
(
status: :success
)
expect_any_instance_of
(
Projects
::
UpdateMirrorService
).
to
receive
(
:execute
).
and_return
(
status: :success
)
...
@@ -14,16 +15,11 @@ describe RepositoryUpdateMirrorWorker do
...
@@ -14,16 +15,11 @@ describe RepositoryUpdateMirrorWorker do
end
end
it
'sets status as failed when update mirror service executes with errors'
do
it
'sets status as failed when update mirror service executes with errors'
do
error_message
=
'fail!'
allow_any_instance_of
(
Projects
::
UpdateMirrorService
).
to
receive
(
:execute
).
and_return
(
status: :error
,
message:
'error'
)
expect_any_instance_of
(
Projects
::
UpdateMirrorService
).
to
receive
(
:execute
).
and_return
(
status: :error
,
message:
error_message
)
expect
{
subject
.
perform
(
project
.
id
)
}.
to
raise_error
(
RepositoryUpdateMirrorWorker
::
UpdateError
,
'error'
)
expect
do
subject
.
perform
(
project
.
id
)
end
.
to
raise_error
(
RepositoryUpdateMirrorWorker
::
UpdateError
,
error_message
)
expect
(
project
.
reload
.
import_status
).
to
eq
(
'failed'
)
expect
(
project
.
reload
.
import_status
).
to
eq
(
'failed'
)
end
end
end
context
'with another worker already running'
do
context
'with another worker already running'
do
it
'returns nil'
do
it
'returns nil'
do
...
@@ -33,44 +29,54 @@ describe RepositoryUpdateMirrorWorker do
...
@@ -33,44 +29,54 @@ describe RepositoryUpdateMirrorWorker do
end
end
end
end
context
'with unexpected error'
do
it
'marks mirror as failed when an error occurs'
do
it
'marks mirror as failed'
do
mirror
=
create
(
:project
,
:repository
,
:mirror
,
:import_scheduled
)
allow_any_instance_of
(
Projects
::
UpdateMirrorService
).
to
receive
(
:execute
).
and_raise
(
RuntimeError
)
allow_any_instance_of
(
Projects
::
UpdateMirrorService
).
to
receive
(
:execute
).
and_raise
(
RuntimeError
)
expect
do
expect
{
subject
.
perform
(
project
.
id
)
}.
to
raise_error
(
RepositoryUpdateMirrorWorker
::
UpdateError
)
subject
.
perform
(
mirror
.
id
)
expect
(
project
.
reload
.
import_status
).
to
eq
(
'failed'
)
end
.
to
raise_error
(
RepositoryUpdateMirrorWorker
::
UpdateError
)
expect
(
mirror
.
reload
.
import_status
).
to
eq
(
'failed'
)
end
end
end
context
'threshold_reached?'
do
context
'reschedule mirrors'
do
let
(
:mirror
)
{
create
(
:project
,
:repository
,
:mirror
,
:import_scheduled
)
}
before
do
allow_any_instance_of
(
Projects
::
UpdateMirrorService
).
to
receive
(
:execute
).
and_return
(
status: :success
)
end
context
'when we obtain the lease'
do
before
do
before
do
expect_any_instance_of
(
Projects
::
UpdateMirrorService
).
to
receive
(
:execute
).
and_return
(
status: :success
)
allow_any_instance_of
(
Gitlab
::
ExclusiveLease
).
to
receive
(
:try_obtain
).
and_return
(
true
)
end
end
context
'with threshold_reached? true'
do
it
'performs UpdateAllMirrorsWorker when reschedule_immediately? returns true'
do
it
'schedules UpdateAllMirrorsWorker'
do
allow
(
Gitlab
::
Mirror
).
to
receive
(
:reschedule_immediately?
).
and_return
(
true
)
expect
(
Gitlab
::
Mirror
).
to
receive
(
:threshold_reached?
).
and_return
(
true
)
expect
(
UpdateAllMirrorsWorker
).
to
receive
(
:perform_async
)
expect
(
UpdateAllMirrorsWorker
).
to
receive
(
:perform_async
)
.
once
subject
.
perform
(
mirror
.
id
)
subject
.
perform
(
project
.
id
)
end
it
'does not perform UpdateAllMirrorsWorker when reschedule_immediately? returns false'
do
allow
(
Gitlab
::
Mirror
).
to
receive
(
:reschedule_immediately?
).
and_return
(
false
)
expect
(
UpdateAllMirrorsWorker
).
not_to
receive
(
:perform_async
)
subject
.
perform
(
project
.
id
)
end
end
end
end
context
'with threshold_reached? false'
do
it
'does not perform UpdateAllMirrorsWorker when we cannot obtain the lease'
do
it
'does not schedule UpdateAllMirrorsWorker'
do
allow_any_instance_of
(
Gitlab
::
ExclusiveLease
).
to
receive
(
:try_obtain
).
and_return
(
false
)
expect
(
Gitlab
::
Mirror
).
to
receive
(
:threshold_reached?
).
and_return
(
false
)
expect
(
UpdateAllMirrorsWorker
).
not_to
receive
(
:perform_async
)
expect
(
UpdateAllMirrorsWorker
).
not_to
receive
(
:perform_async
)
subject
.
perform
(
mirror
.
id
)
subject
.
perform
(
project
.
id
)
end
end
it
'does not perform UpdateAllMirrorsWorker when the lease already exists'
do
allow_any_instance_of
(
Gitlab
::
ExclusiveLease
).
to
receive
(
:exists?
).
and_return
(
true
)
expect
(
UpdateAllMirrorsWorker
).
not_to
receive
(
:perform_async
)
subject
.
perform
(
project
.
id
)
end
end
end
end
end
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment