Commit 397aa1b4 authored by Alexandru Croitor's avatar Alexandru Croitor

Rename StuckImportJobsWorker to StuckProjectImportJobsWorker

We now have 2 types of imports, project imports and jira issue
imports as well as 2 types of workers to check for stuck imports.
Renaming the classes should help to make the code easier to
read and understand.
parent 4c1dff36
...@@ -11,7 +11,7 @@ module ImportState ...@@ -11,7 +11,7 @@ module ImportState
# Refreshes the expiration time of the associated import job ID. # Refreshes the expiration time of the associated import job ID.
# #
# This method can be used by asynchronous importers to refresh the status, # This method can be used by asynchronous importers to refresh the status,
# preventing the StuckImportJobsWorker from marking the import as failed. # preventing the Gitlab::Import::StuckProjectImportJobsWorker from marking the import as failed.
def refresh_jid_expiration def refresh_jid_expiration
return unless jid return unless jid
......
...@@ -147,6 +147,14 @@ ...@@ -147,6 +147,14 @@
:weight: 1 :weight: 1
:idempotent: :idempotent:
:tags: [] :tags: []
- :name: cronjob:import_stuck_project_import_jobs
:feature_category: :importers
:has_external_dependencies:
:urgency: :low
:resource_boundary: :cpu
:weight: 1
:idempotent:
:tags: []
- :name: cronjob:issue_due_scheduler - :name: cronjob:issue_due_scheduler
:feature_category: :issue_tracking :feature_category: :issue_tracking
:has_external_dependencies: :has_external_dependencies:
......
# frozen_string_literal: true
module Gitlab
module Import
class StuckProjectImportJobsWorker # rubocop:disable Scalability/IdempotentWorker
include Gitlab::Import::StuckImportJob
private
def track_metrics(with_jid_count, without_jid_count)
Gitlab::Metrics.add_event(
:stuck_import_jobs,
projects_without_jid_count: without_jid_count,
projects_with_jid_count: with_jid_count
)
end
def enqueued_import_states
ProjectImportState.with_status([:scheduled, :started])
end
end
end
end
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
# - It keeps track of the jobs so we know how many jobs are running for the # - It keeps track of the jobs so we know how many jobs are running for the
# project # project
# - It refreshes the import jid, so it doesn't get cleaned up by the # - It refreshes the import jid, so it doesn't get cleaned up by the
# `StuckImportJobsWorker` # `Gitlab::Import::StuckProjectImportJobsWorker`
# - It marks the import as failed if a job failed to many times # - It marks the import as failed if a job failed to many times
# - It marks the import as finished when all remaining jobs are done # - It marks the import as finished when all remaining jobs are done
module Gitlab module Gitlab
......
...@@ -451,9 +451,9 @@ Settings.cron_jobs['trending_projects_worker']['job_class'] = 'TrendingProjectsW ...@@ -451,9 +451,9 @@ Settings.cron_jobs['trending_projects_worker']['job_class'] = 'TrendingProjectsW
Settings.cron_jobs['remove_unreferenced_lfs_objects_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['remove_unreferenced_lfs_objects_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['remove_unreferenced_lfs_objects_worker']['cron'] ||= '20 0 * * *' Settings.cron_jobs['remove_unreferenced_lfs_objects_worker']['cron'] ||= '20 0 * * *'
Settings.cron_jobs['remove_unreferenced_lfs_objects_worker']['job_class'] = 'RemoveUnreferencedLfsObjectsWorker' Settings.cron_jobs['remove_unreferenced_lfs_objects_worker']['job_class'] = 'RemoveUnreferencedLfsObjectsWorker'
Settings.cron_jobs['stuck_import_jobs_worker'] ||= Settingslogic.new({}) Settings.cron_jobs['import_stuck_project_import_jobs'] ||= Settingslogic.new({})
Settings.cron_jobs['stuck_import_jobs_worker']['cron'] ||= '15 * * * *' Settings.cron_jobs['import_stuck_project_import_jobs']['cron'] ||= '15 * * * *'
Settings.cron_jobs['stuck_import_jobs_worker']['job_class'] = 'StuckImportJobsWorker' Settings.cron_jobs['import_stuck_project_import_jobs']['job_class'] = 'Gitlab::Import::StuckProjectImportJobsWorker'
Settings.cron_jobs['jira_import_stuck_jira_import_jobs'] ||= Settingslogic.new({}) Settings.cron_jobs['jira_import_stuck_jira_import_jobs'] ||= Settingslogic.new({})
Settings.cron_jobs['jira_import_stuck_jira_import_jobs']['cron'] ||= '* 0/15 * * *' Settings.cron_jobs['jira_import_stuck_jira_import_jobs']['cron'] ||= '* 0/15 * * *'
Settings.cron_jobs['jira_import_stuck_jira_import_jobs']['job_class'] = 'Gitlab::JiraImport::StuckJiraImportJobsWorker' Settings.cron_jobs['jira_import_stuck_jira_import_jobs']['job_class'] = 'Gitlab::JiraImport::StuckJiraImportJobsWorker'
......
# frozen_string_literal: true
class MigrateStuckImportJobsQueueToStuckProjectImportJobs < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
sidekiq_queue_migrate 'cronjob:stuck_import_jobs', to: 'cronjob:import_stuck_project_import_jobs'
end
def down
sidekiq_queue_migrate 'cronjob:import_stuck_project_import_jobs', to: 'cronjob:stuck_import_jobs'
end
end
...@@ -13778,6 +13778,7 @@ COPY "schema_migrations" (version) FROM STDIN; ...@@ -13778,6 +13778,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200522235146 20200522235146
20200525114553 20200525114553
20200525121014 20200525121014
20200525144525
20200526000407 20200526000407
20200526013844 20200526013844
20200526120714 20200526120714
......
...@@ -121,12 +121,12 @@ also reduce pressure on the system as a whole. ...@@ -121,12 +121,12 @@ also reduce pressure on the system as a whole.
## Refreshing import JIDs ## Refreshing import JIDs
GitLab includes a worker called `StuckImportJobsWorker` that will periodically GitLab includes a worker called `Gitlab::Import::StuckProjectImportJobsWorker`
run and mark project imports as failed if they have been running for more than that will periodically run and mark project imports as failed if they have been
15 hours. For GitHub projects, this poses a bit of a problem: importing large running for more than 15 hours. For GitHub projects, this poses a bit of a
projects could take several hours depending on how often we hit the GitHub rate problem: importing large projects could take several hours depending on how
limit (more on this below), but we don't want `StuckImportJobsWorker` to mark often we hit the GitHub rate limit (more on this below), but we don't want
our import as failed because of this. `Gitlab::Import::StuckProjectImportJobsWorker` to mark our import as failed because of this.
To prevent this from happening we periodically refresh the expiration time of To prevent this from happening we periodically refresh the expiration time of
the import process. This works by storing the JID of the import job in the the import process. This works by storing the JID of the import job in the
......
...@@ -44,19 +44,34 @@ WARN: Work still in progress <struct with JID> ...@@ -44,19 +44,34 @@ WARN: Work still in progress <struct with JID>
### Timeouts ### Timeouts
Timeout errors occur due to the `StuckImportJobsWorker` marking the process as failed: Timeout errors occur due to the `Gitlab::Import::StuckProjectImportJobsWorker` marking the process as failed:
```ruby ```ruby
class StuckImportJobsWorker module Gitlab
include ApplicationWorker module Import
include CronjobQueue class StuckProjectImportJobsWorker
include Gitlab::Import::StuckImportJob
# ...
end
end
end
module Gitlab
module Import
module StuckImportJob
# ...
IMPORT_JOBS_EXPIRATION = 15.hours.to_i IMPORT_JOBS_EXPIRATION = 15.hours.to_i
# ...
def perform def perform
imports_without_jid_count = mark_imports_without_jid_as_failed! stuck_imports_without_jid_count = mark_imports_without_jid_as_failed!
imports_with_jid_count = mark_imports_with_jid_as_failed! stuck_imports_with_jid_count = mark_imports_with_jid_as_failed!
...
track_metrics(stuck_imports_with_jid_count, stuck_imports_without_jid_count)
end
# ...
end
end
end
``` ```
```shell ```shell
......
...@@ -25,7 +25,7 @@ RSpec.describe Gitlab::SidekiqConfig do ...@@ -25,7 +25,7 @@ RSpec.describe Gitlab::SidekiqConfig do
it 'expands queue namespaces to concrete queue names' do it 'expands queue namespaces to concrete queue names' do
queues = described_class.expand_queues(%w[cronjob]) queues = described_class.expand_queues(%w[cronjob])
expect(queues).to include('cronjob:stuck_import_jobs') expect(queues).to include('cronjob:import_stuck_project_import_jobs')
expect(queues).to include('cronjob:jira_import_stuck_jira_import_jobs') expect(queues).to include('cronjob:jira_import_stuck_jira_import_jobs')
expect(queues).to include('cronjob:stuck_merge_jobs') expect(queues).to include('cronjob:stuck_merge_jobs')
end end
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
# The original import JID is the JID of the RepositoryImportWorker job, # The original import JID is the JID of the RepositoryImportWorker job,
# which will be removed once that job completes. Reusing that JID could # which will be removed once that job completes. Reusing that JID could
# result in StuckImportJobsWorker marking the job as stuck before we get # result in Gitlab::Import::StuckProjectImportJobsWorker marking the job
# to running Stage::ImportRepositoryWorker. # as stuck before we get to running Stage::ImportRepositoryWorker.
# #
# We work around this by setting the JID to a custom generated one, then # We work around this by setting the JID to a custom generated one, then
# refreshing it in the various stages whenever necessary. # refreshing it in the various stages whenever necessary.
...@@ -13,8 +13,7 @@ module Gitlab ...@@ -13,8 +13,7 @@ module Gitlab
def self.set_jid(import_state) def self.set_jid(import_state)
jid = generate_jid(import_state) jid = generate_jid(import_state)
Gitlab::SidekiqStatus Gitlab::SidekiqStatus.set(jid, Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION)
.set(jid, Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION)
import_state.update_column(:jid, jid) import_state.update_column(:jid, jid)
end end
......
...@@ -77,7 +77,7 @@ describe Gitlab::SidekiqConfig::CliMethods do ...@@ -77,7 +77,7 @@ describe Gitlab::SidekiqConfig::CliMethods do
describe '.expand_queues' do describe '.expand_queues' do
let(:worker_queues) do let(:worker_queues) do
[ [
'cronjob:stuck_import_jobs', 'cronjob:import_stuck_project_import_jobs',
'cronjob:jira_import_stuck_jira_import_jobs', 'cronjob:jira_import_stuck_jira_import_jobs',
'cronjob:stuck_merge_jobs', 'cronjob:stuck_merge_jobs',
'post_receive' 'post_receive'
...@@ -93,12 +93,22 @@ describe Gitlab::SidekiqConfig::CliMethods do ...@@ -93,12 +93,22 @@ describe Gitlab::SidekiqConfig::CliMethods do
allow(described_class).to receive(:worker_queues).and_return(worker_queues) allow(described_class).to receive(:worker_queues).and_return(worker_queues)
expect(described_class.expand_queues(['cronjob'])) expect(described_class.expand_queues(['cronjob']))
.to contain_exactly('cronjob', 'cronjob:stuck_import_jobs', 'cronjob:jira_import_stuck_jira_import_jobs', 'cronjob:stuck_merge_jobs') .to contain_exactly(
'cronjob',
'cronjob:import_stuck_project_import_jobs',
'cronjob:jira_import_stuck_jira_import_jobs',
'cronjob:stuck_merge_jobs'
)
end end
it 'expands queue namespaces to concrete queue names' do it 'expands queue namespaces to concrete queue names' do
expect(described_class.expand_queues(['cronjob'], worker_queues)) expect(described_class.expand_queues(['cronjob'], worker_queues))
.to contain_exactly('cronjob', 'cronjob:stuck_import_jobs', 'cronjob:jira_import_stuck_jira_import_jobs', 'cronjob:stuck_merge_jobs') .to contain_exactly(
'cronjob',
'cronjob:import_stuck_project_import_jobs',
'cronjob:jira_import_stuck_jira_import_jobs',
'cronjob:stuck_merge_jobs'
)
end end
it 'lets concrete queue names pass through' do it 'lets concrete queue names pass through' do
......
...@@ -18,7 +18,7 @@ describe Gitlab::SidekiqConfig do ...@@ -18,7 +18,7 @@ describe Gitlab::SidekiqConfig do
expect(queues).to include('post_receive') expect(queues).to include('post_receive')
expect(queues).to include('merge') expect(queues).to include('merge')
expect(queues).to include('cronjob:stuck_import_jobs') expect(queues).to include('cronjob:import_stuck_project_import_jobs')
expect(queues).to include('cronjob:jira_import_stuck_jira_import_jobs') expect(queues).to include('cronjob:jira_import_stuck_jira_import_jobs')
expect(queues).to include('mailers') expect(queues).to include('mailers')
expect(queues).to include('default') expect(queues).to include('default')
......
...@@ -16,7 +16,7 @@ describe Gitlab::SidekiqVersioning::Manager do ...@@ -16,7 +16,7 @@ describe Gitlab::SidekiqVersioning::Manager do
expect(queues).to include('post_receive') expect(queues).to include('post_receive')
expect(queues).to include('repository_fork') expect(queues).to include('repository_fork')
expect(queues).to include('cronjob') expect(queues).to include('cronjob')
expect(queues).to include('cronjob:stuck_import_jobs') expect(queues).to include('cronjob:import_stuck_project_import_jobs')
expect(queues).to include('cronjob:jira_import_stuck_jira_import_jobs') expect(queues).to include('cronjob:jira_import_stuck_jira_import_jobs')
expect(queues).to include('cronjob:stuck_merge_jobs') expect(queues).to include('cronjob:stuck_merge_jobs')
expect(queues).to include('unknown') expect(queues).to include('unknown')
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Import::StuckProjectImportJobsWorker do
let(:worker) { described_class.new }
describe 'with scheduled import_status' do
it_behaves_like 'stuck import job detection' do
let(:import_state) { create(:project, :import_scheduled).import_state }
before do
import_state.update(jid: '123')
end
end
end
describe 'with started import_status' do
it_behaves_like 'stuck import job detection' do
let(:import_state) { create(:project, :import_started).import_state }
before do
import_state.update(jid: '123')
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