From 2e8babc771fd88d05334a9001d36e40aa86e0bd9 Mon Sep 17 00:00:00 2001 From: Sam Word <sword@gitlab.com> Date: Thu, 8 Feb 2024 19:24:20 +0000 Subject: [PATCH] Added RefreshImportWorker to Bitbucket Cloud/Server stage workers Adding RefreshImportWorker to Bitbucket Cloud and Server importer stage workers so that their job IDs are refreshed when a stage begins preventing StuckImportWroker from mistakenly thinking a slow import is stuck. Changelog: fixed --- .rubocop_todo/style/arguments_forwarding.yml | 1 - .rubocop_todo/style/guard_clause.yml | 1 - app/workers/all_queues.yml | 9 ++ .../gitlab/bitbucket_import/stage_methods.rb | 4 + .../bitbucket_server_import/stage_methods.rb | 4 + .../gitlab/github_import/stage_methods.rb | 2 +- .../stage/import_issues_notes_worker.rb | 2 - .../stage/import_issues_worker.rb | 2 - .../stage/import_lfs_objects_worker.rb | 2 - .../import_pull_requests_notes_worker.rb | 2 - .../stage/import_pull_requests_worker.rb | 2 - .../stage/import_lfs_objects_worker.rb | 2 - .../stage/import_notes_worker.rb | 2 - .../stage/import_pull_requests_worker.rb | 2 - .../refresh_import_jid_worker.rb | 37 +------ .../import/refresh_import_jid_worker.rb | 41 ++++++++ config/sidekiq_queues.yml | 2 + lib/gitlab/github_import/parallel_importer.rb | 2 +- spec/support/rspec_order_todo.yml | 1 - .../stage_methods_shared_examples.rb | 13 ++- .../stage_methods_shared_examples.rb | 22 +++++ .../stage_methods_shared_examples.rb | 2 +- spec/workers/every_sidekiq_worker_spec.rb | 2 +- .../refresh_import_jid_worker_spec.rb | 98 +------------------ .../import/refresh_import_jid_worker_spec.rb | 87 ++++++++++++++++ 25 files changed, 192 insertions(+), 152 deletions(-) create mode 100644 app/workers/gitlab/import/refresh_import_jid_worker.rb create mode 100644 spec/workers/gitlab/import/refresh_import_jid_worker_spec.rb diff --git a/.rubocop_todo/style/arguments_forwarding.yml b/.rubocop_todo/style/arguments_forwarding.yml index b72751ed27946..53ae5e4a96c71 100644 --- a/.rubocop_todo/style/arguments_forwarding.yml +++ b/.rubocop_todo/style/arguments_forwarding.yml @@ -47,7 +47,6 @@ Style/ArgumentsForwarding: - 'app/workers/concerns/limited_capacity/worker.rb' - 'app/workers/concerns/reactive_cacheable_worker.rb' - 'app/workers/concerns/reenqueuer.rb' - - 'app/workers/gitlab/github_import/refresh_import_jid_worker.rb' - 'app/workers/pages_worker.rb' - 'config/initializers/6_labkit_middleware.rb' - 'config/initializers/active_record_table_definition.rb' diff --git a/.rubocop_todo/style/guard_clause.yml b/.rubocop_todo/style/guard_clause.yml index 9896356b1f603..3ff511a25b76c 100644 --- a/.rubocop_todo/style/guard_clause.yml +++ b/.rubocop_todo/style/guard_clause.yml @@ -234,7 +234,6 @@ Style/GuardClause: - 'app/workers/container_registry/migration/guard_worker.rb' - 'app/workers/deployments/hooks_worker.rb' - 'app/workers/deployments/link_merge_request_worker.rb' - - 'app/workers/gitlab/github_import/refresh_import_jid_worker.rb' - 'app/workers/google_cloud/create_cloudsql_instance_worker.rb' - 'app/workers/packages/cleanup/execute_policy_worker.rb' - 'app/workers/packages/maven/metadata/sync_worker.rb' diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 269fac4151dd4..1413638e903db 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -3198,6 +3198,15 @@ :weight: 2 :idempotent: true :tags: [] +- :name: import_refresh_import_jid + :worker_name: Gitlab::Import::RefreshImportJidWorker + :feature_category: :importers + :has_external_dependencies: false + :urgency: :low + :resource_boundary: :unknown + :weight: 1 + :idempotent: true + :tags: [] - :name: incident_management_close_incident :worker_name: IncidentManagement::CloseIncidentWorker :feature_category: :incident_management diff --git a/app/workers/concerns/gitlab/bitbucket_import/stage_methods.rb b/app/workers/concerns/gitlab/bitbucket_import/stage_methods.rb index 51e2f5cff227d..3af4f24438aff 100644 --- a/app/workers/concerns/gitlab/bitbucket_import/stage_methods.rb +++ b/app/workers/concerns/gitlab/bitbucket_import/stage_methods.rb @@ -16,6 +16,8 @@ module StageMethods sidekiq_options dead: false, retry: 6 + sidekiq_options status_expiration: Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION + sidekiq_retries_exhausted do |msg, e| Gitlab::Import::ImportFailureService.track( project_id: msg['args'][0], @@ -33,6 +35,8 @@ def perform(project_id) return unless project + Import::RefreshImportJidWorker.perform_in_the_future(project_id, jid) + import(project) info(project_id, message: 'stage finished') diff --git a/app/workers/concerns/gitlab/bitbucket_server_import/stage_methods.rb b/app/workers/concerns/gitlab/bitbucket_server_import/stage_methods.rb index cf5710e6108c3..304547ac1cc35 100644 --- a/app/workers/concerns/gitlab/bitbucket_server_import/stage_methods.rb +++ b/app/workers/concerns/gitlab/bitbucket_server_import/stage_methods.rb @@ -16,6 +16,8 @@ module StageMethods sidekiq_options dead: false, retry: 6 + sidekiq_options status_expiration: Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION + sidekiq_retries_exhausted do |msg, e| Gitlab::Import::ImportFailureService.track( project_id: msg['args'][0], @@ -31,6 +33,8 @@ def perform(project_id) return unless (project = find_project(project_id)) + Import::RefreshImportJidWorker.perform_in_the_future(project_id, jid) + import(project) info(project_id, message: 'stage finished') diff --git a/app/workers/concerns/gitlab/github_import/stage_methods.rb b/app/workers/concerns/gitlab/github_import/stage_methods.rb index 69cf6f424af02..f6a46f50ca388 100644 --- a/app/workers/concerns/gitlab/github_import/stage_methods.rb +++ b/app/workers/concerns/gitlab/github_import/stage_methods.rb @@ -62,7 +62,7 @@ def perform(project_id) return end - RefreshImportJidWorker.perform_in_the_future(project.id, jid) + Import::RefreshImportJidWorker.perform_in_the_future(project.id, jid) client = GithubImport.new_client_for(project) diff --git a/app/workers/gitlab/bitbucket_import/stage/import_issues_notes_worker.rb b/app/workers/gitlab/bitbucket_import/stage/import_issues_notes_worker.rb index cbd67099086a8..af7927b80a819 100644 --- a/app/workers/gitlab/bitbucket_import/stage/import_issues_notes_worker.rb +++ b/app/workers/gitlab/bitbucket_import/stage/import_issues_notes_worker.rb @@ -12,8 +12,6 @@ class ImportIssuesNotesWorker # rubocop:disable Scalability/IdempotentWorker def import(project) waiter = importer_class.new(project).execute - project.import_state.refresh_jid_expiration - AdvanceStageWorker.perform_async( project.id, { waiter.key => waiter.jobs_remaining }, diff --git a/app/workers/gitlab/bitbucket_import/stage/import_issues_worker.rb b/app/workers/gitlab/bitbucket_import/stage/import_issues_worker.rb index 31a11d802c737..d2dac824e8139 100644 --- a/app/workers/gitlab/bitbucket_import/stage/import_issues_worker.rb +++ b/app/workers/gitlab/bitbucket_import/stage/import_issues_worker.rb @@ -12,8 +12,6 @@ class ImportIssuesWorker # rubocop:disable Scalability/IdempotentWorker def import(project) waiter = importer_class.new(project).execute - project.import_state.refresh_jid_expiration - AdvanceStageWorker.perform_async( project.id, { waiter.key => waiter.jobs_remaining }, diff --git a/app/workers/gitlab/bitbucket_import/stage/import_lfs_objects_worker.rb b/app/workers/gitlab/bitbucket_import/stage/import_lfs_objects_worker.rb index c88a1be34466b..328a66dcdca9e 100644 --- a/app/workers/gitlab/bitbucket_import/stage/import_lfs_objects_worker.rb +++ b/app/workers/gitlab/bitbucket_import/stage/import_lfs_objects_worker.rb @@ -12,8 +12,6 @@ class ImportLfsObjectsWorker # rubocop:disable Scalability/IdempotentWorker def import(project) waiter = importer_class.new(project).execute - project.import_state.refresh_jid_expiration - AdvanceStageWorker.perform_async( project.id, { waiter.key => waiter.jobs_remaining }, diff --git a/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_notes_worker.rb b/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_notes_worker.rb index 36d60c7246c58..fcabe80abc49d 100644 --- a/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_notes_worker.rb +++ b/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_notes_worker.rb @@ -12,8 +12,6 @@ class ImportPullRequestsNotesWorker # rubocop:disable Scalability/IdempotentWork def import(project) waiter = importer_class.new(project).execute - project.import_state.refresh_jid_expiration - AdvanceStageWorker.perform_async( project.id, { waiter.key => waiter.jobs_remaining }, diff --git a/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker.rb b/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker.rb index 3f85c832d5098..373dfcdb1f787 100644 --- a/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker.rb +++ b/app/workers/gitlab/bitbucket_import/stage/import_pull_requests_worker.rb @@ -12,8 +12,6 @@ class ImportPullRequestsWorker # rubocop:disable Scalability/IdempotentWorker def import(project) waiter = importer_class.new(project).execute - project.import_state.refresh_jid_expiration - AdvanceStageWorker.perform_async( project.id, { waiter.key => waiter.jobs_remaining }, diff --git a/app/workers/gitlab/bitbucket_server_import/stage/import_lfs_objects_worker.rb b/app/workers/gitlab/bitbucket_server_import/stage/import_lfs_objects_worker.rb index 1002047225c93..020205dcddbe9 100644 --- a/app/workers/gitlab/bitbucket_server_import/stage/import_lfs_objects_worker.rb +++ b/app/workers/gitlab/bitbucket_server_import/stage/import_lfs_objects_worker.rb @@ -12,8 +12,6 @@ class ImportLfsObjectsWorker # rubocop:disable Scalability/IdempotentWorker def import(project) waiter = importer_class.new(project).execute - project.import_state.refresh_jid_expiration - AdvanceStageWorker.perform_async( project.id, { waiter.key => waiter.jobs_remaining }, diff --git a/app/workers/gitlab/bitbucket_server_import/stage/import_notes_worker.rb b/app/workers/gitlab/bitbucket_server_import/stage/import_notes_worker.rb index b30f93058298a..8020dc7ab3af9 100644 --- a/app/workers/gitlab/bitbucket_server_import/stage/import_notes_worker.rb +++ b/app/workers/gitlab/bitbucket_server_import/stage/import_notes_worker.rb @@ -12,8 +12,6 @@ class ImportNotesWorker # rubocop:disable Scalability/IdempotentWorker def import(project) waiter = importer_class.new(project).execute - project.import_state.refresh_jid_expiration - AdvanceStageWorker.perform_async( project.id, { waiter.key => waiter.jobs_remaining }, diff --git a/app/workers/gitlab/bitbucket_server_import/stage/import_pull_requests_worker.rb b/app/workers/gitlab/bitbucket_server_import/stage/import_pull_requests_worker.rb index 9e3d570e20dfb..c39665b682965 100644 --- a/app/workers/gitlab/bitbucket_server_import/stage/import_pull_requests_worker.rb +++ b/app/workers/gitlab/bitbucket_server_import/stage/import_pull_requests_worker.rb @@ -12,8 +12,6 @@ class ImportPullRequestsWorker # rubocop:disable Scalability/IdempotentWorker def import(project) waiter = importer_class.new(project).execute - project.import_state.refresh_jid_expiration - AdvanceStageWorker.perform_async( project.id, { waiter.key => waiter.jobs_remaining }, diff --git a/app/workers/gitlab/github_import/refresh_import_jid_worker.rb b/app/workers/gitlab/github_import/refresh_import_jid_worker.rb index dfc581f201b69..ee7e45889bd84 100644 --- a/app/workers/gitlab/github_import/refresh_import_jid_worker.rb +++ b/app/workers/gitlab/github_import/refresh_import_jid_worker.rb @@ -9,42 +9,11 @@ class RefreshImportJidWorker # rubocop:disable Scalability/IdempotentWorker include GithubImport::Queue - sidekiq_options retry: 5 - - # The interval to schedule new instances of this job at. - INTERVAL = 5.minutes.to_i - def self.perform_in_the_future(*args) - perform_in(INTERVAL, *args) - end - - # project_id - The ID of the project that is being imported. - # check_job_id - The ID of the job for which to check the status. - def perform(project_id, check_job_id) - import_state = find_import_state(project_id) - return unless import_state - - if SidekiqStatus.running?(check_job_id) - # As long as the worker is running we want to keep refreshing - # the worker's JID as well as the import's JID. - Gitlab::SidekiqStatus.expire(check_job_id, Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION) - Gitlab::SidekiqStatus.set(import_state.jid, Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION) - - self.class.perform_in_the_future(project_id, check_job_id) - end - - # If the job is no longer running there's nothing else we need to do. If - # the clone job completed successfully it will have scheduled the next - # stage, if it died there's nothing we can do anyway. - end - - # rubocop: disable CodeReuse/ActiveRecord - def find_import_state(project_id) - ProjectImportState.select(:jid) - .with_status(:started) - .find_by(project_id: project_id) + # Delegate to new version of this job so stale sidekiq nodes can still + # run instead of no-op + Gitlab::Import::RefreshImportJidWorker.perform_in_the_future(*args) end - # rubocop: enable CodeReuse/ActiveRecord end end end diff --git a/app/workers/gitlab/import/refresh_import_jid_worker.rb b/app/workers/gitlab/import/refresh_import_jid_worker.rb new file mode 100644 index 0000000000000..f9a7bf870afcb --- /dev/null +++ b/app/workers/gitlab/import/refresh_import_jid_worker.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module Gitlab + module Import + class RefreshImportJidWorker + include ApplicationWorker + + data_consistency :delayed + idempotent! + + feature_category :importers + sidekiq_options dead: false + + sidekiq_options retry: 5 + + # The interval to schedule new instances of this job at. + INTERVAL = 5.minutes.to_i + + def self.perform_in_the_future(*args) + perform_in(INTERVAL, *args) + end + + # project_id - The ID of the project that is being imported. + # check_job_id - The ID of the job for which to check the status. + # params - to avoid multiple releases if parameters change + def perform(project_id, check_job_id, _params = {}) + return unless SidekiqStatus.running?(check_job_id) + + import_state_jid = ProjectImportState.jid_by(project_id: project_id, status: :started)&.jid + return unless import_state_jid + + # As long as the worker is running we want to keep refreshing + # the worker's JID as well as the import's JID. + Gitlab::SidekiqStatus.expire(check_job_id, Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION) + Gitlab::SidekiqStatus.set(import_state_jid, Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION) + + self.class.perform_in_the_future(project_id, check_job_id) + end + end + end +end diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index 994cdb7d67aee..a7182e334180c 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -373,6 +373,8 @@ - 1 - - import_issues_csv - 2 +- - import_refresh_import_jid + - 1 - - incident_management - 2 - - incident_management_apply_incident_sla_exceeded_label diff --git a/lib/gitlab/github_import/parallel_importer.rb b/lib/gitlab/github_import/parallel_importer.rb index a71590c02f82e..e045c424fe1bb 100644 --- a/lib/gitlab/github_import/parallel_importer.rb +++ b/lib/gitlab/github_import/parallel_importer.rb @@ -35,7 +35,7 @@ def initialize(project) def execute Gitlab::Import::SetAsyncJid.set_jid(project.import_state) - # We need to track this job's status for use by Gitlab::GithubImport::RefreshImportJidWorker. + # We need to track this job's status for use by Gitlab::Import::RefreshImportJidWorker. Stage::ImportRepositoryWorker .with_status .perform_async(project.id) diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml index 22d8871b71877..9e1038b4d4edd 100644 --- a/spec/support/rspec_order_todo.yml +++ b/spec/support/rspec_order_todo.yml @@ -9489,7 +9489,6 @@ - './spec/workers/gitlab/github_import/import_issue_worker_spec.rb' - './spec/workers/gitlab/github_import/import_note_worker_spec.rb' - './spec/workers/gitlab/github_import/import_pull_request_worker_spec.rb' -- './spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb' - './spec/workers/gitlab/github_import/stage/finish_import_worker_spec.rb' - './spec/workers/gitlab/github_import/stage/import_base_data_worker_spec.rb' - './spec/workers/gitlab/github_import/stage/import_issue_events_worker_spec.rb' diff --git a/spec/support/shared_examples/lib/gitlab/bitbucket_import/stage_methods_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/bitbucket_import/stage_methods_shared_examples.rb index f128aa92a5317..46771afaa3422 100644 --- a/spec/support/shared_examples/lib/gitlab/bitbucket_import/stage_methods_shared_examples.rb +++ b/spec/support/shared_examples/lib/gitlab/bitbucket_import/stage_methods_shared_examples.rb @@ -16,7 +16,7 @@ end end - describe '.perform' do + describe '#perform' do let(:worker) { described_class.new } it 'executes the import' do @@ -25,5 +25,16 @@ worker.perform(project.id) end + + it 'queues RefreshImportJidWorker' do + allow(worker).to receive(:import) + allow(worker).to receive(:jid).and_return('mock_jid') + + expect(Gitlab::Import::RefreshImportJidWorker) + .to receive(:perform_in_the_future) + .with(project.id, 'mock_jid') + + worker.perform(project.id) + end end end diff --git a/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/stage_methods_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/stage_methods_shared_examples.rb index 1246dd2979b9c..c73c9f6028228 100644 --- a/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/stage_methods_shared_examples.rb +++ b/spec/support/shared_examples/lib/gitlab/bitbucket_server_import/stage_methods_shared_examples.rb @@ -15,4 +15,26 @@ described_class.sidekiq_retries_exhausted_block.call(job, StandardError.new) end end + + describe '#perform' do + let(:worker) { described_class.new } + + it 'executes the import' do + expect(worker).to receive(:import).with(project).once + expect(Gitlab::BitbucketServerImport::Logger).to receive(:info).twice + + worker.perform(project.id) + end + + it 'queues RefreshImportJidWorker' do + allow(worker).to receive(:import) + allow(worker).to receive(:jid).and_return('mock_jid') + + expect(Gitlab::Import::RefreshImportJidWorker) + .to receive(:perform_in_the_future) + .with(project.id, 'mock_jid') + + worker.perform(project.id) + end + end end diff --git a/spec/support/shared_examples/workers/gitlab/github_import/stage_methods_shared_examples.rb b/spec/support/shared_examples/workers/gitlab/github_import/stage_methods_shared_examples.rb index b5e3589d86c50..6d064e0c999d3 100644 --- a/spec/support/shared_examples/workers/gitlab/github_import/stage_methods_shared_examples.rb +++ b/spec/support/shared_examples/workers/gitlab/github_import/stage_methods_shared_examples.rb @@ -100,7 +100,7 @@ allow(worker).to receive(:import) allow(worker).to receive(:jid).and_return('mock_jid') - expect(Gitlab::GithubImport::RefreshImportJidWorker) + expect(Gitlab::Import::RefreshImportJidWorker) .to receive(:perform_in_the_future) .with(project.id, 'mock_jid') diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb index 75101c1a24e48..dc2851bd562eb 100644 --- a/spec/workers/every_sidekiq_worker_spec.rb +++ b/spec/workers/every_sidekiq_worker_spec.rb @@ -279,7 +279,6 @@ 'Gitlab::GithubImport::PullRequests::ImportReviewWorker' => 5, 'Gitlab::GithubImport::PullRequests::ImportMergedByWorker' => 5, 'Gitlab::GithubImport::ImportPullRequestWorker' => 5, - 'Gitlab::GithubImport::RefreshImportJidWorker' => 5, 'Gitlab::GithubImport::ReplayEventsWorker' => 5, 'Gitlab::GithubImport::Stage::FinishImportWorker' => 6, 'Gitlab::GithubImport::Stage::ImportBaseDataWorker' => 6, @@ -298,6 +297,7 @@ 'Gitlab::GithubGistsImport::ImportGistWorker' => 5, 'Gitlab::GithubGistsImport::StartImportWorker' => 5, 'Gitlab::GithubGistsImport::FinishImportWorker' => 5, + 'Gitlab::Import::RefreshImportJidWorker' => 5, 'Gitlab::JiraImport::AdvanceStageWorker' => 6, 'Gitlab::JiraImport::ImportIssueWorker' => 5, 'Gitlab::JiraImport::Stage::FinishImportWorker' => 6, diff --git a/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb b/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb index 5d0cb05c8d5ed..70f958b60f6a1 100644 --- a/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb +++ b/spec/workers/gitlab/github_import/refresh_import_jid_worker_spec.rb @@ -6,102 +6,12 @@ let(:worker) { described_class.new } describe '.perform_in_the_future' do - it 'schedules a job in the future' do - expect(described_class) - .to receive(:perform_in) - .with(5.minutes.to_i, 10, '123') + it 'calls Gitlab::Import::RefreshImportJidWorker#perform_in_the_future' do + expect(Gitlab::Import::RefreshImportJidWorker) + .to receive(:perform_in_the_future) + .with(10, '123') described_class.perform_in_the_future(10, '123') end end - - describe '#perform' do - let(:project) { create(:project) } - let(:import_state) { create(:import_state, project: project, jid: '123abc') } - - context 'when the project does not exist' do - it 'does nothing' do - expect(Gitlab::SidekiqStatus) - .not_to receive(:running?) - - worker.perform(-1, '123') - end - end - - context 'when the job is running' do - it 'refreshes the import JID and reschedules itself' do - allow(worker) - .to receive(:find_import_state) - .with(project.id) - .and_return(import_state) - - expect(Gitlab::SidekiqStatus) - .to receive(:running?) - .with('123') - .and_return(true) - - expect(Gitlab::SidekiqStatus) - .to receive(:expire) - .with('123', Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION) - - expect(Gitlab::SidekiqStatus) - .to receive(:set) - .with(import_state.jid, Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION) - - expect(worker.class) - .to receive(:perform_in_the_future) - .with(project.id, '123') - - worker.perform(project.id, '123') - end - end - - context 'when the job is no longer running' do - it 'returns' do - allow(worker) - .to receive(:find_import_state) - .with(project.id) - .and_return(project) - - expect(Gitlab::SidekiqStatus) - .to receive(:running?) - .with('123') - .and_return(false) - - expect(Gitlab::SidekiqStatus) - .not_to receive(:expire) - - expect(Gitlab::SidekiqStatus) - .not_to receive(:set) - - worker.perform(project.id, '123') - end - end - end - - describe '#find_import_state' do - it 'returns a ProjectImportState' do - project = create(:project, :import_started) - - expect(worker.find_import_state(project.id)).to be_an_instance_of(ProjectImportState) - end - - # it 'only selects the import JID field' do - # project = create(:project, :import_started) - # project.import_state.update_attributes(jid: '123abc') - # - # expect(worker.find_project(project.id).attributes) - # .to eq({ 'id' => nil, 'import_jid' => '123abc' }) - # end - - it 'returns nil for a import state for which the import process failed' do - project = create(:project, :import_failed) - - expect(worker.find_import_state(project.id)).to be_nil - end - - it 'returns nil for a non-existing find_import_state' do - expect(worker.find_import_state(-1)).to be_nil - end - end end diff --git a/spec/workers/gitlab/import/refresh_import_jid_worker_spec.rb b/spec/workers/gitlab/import/refresh_import_jid_worker_spec.rb new file mode 100644 index 0000000000000..be4a585d60ed6 --- /dev/null +++ b/spec/workers/gitlab/import/refresh_import_jid_worker_spec.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Import::RefreshImportJidWorker, feature_category: :importers do + let(:worker) { described_class.new } + + describe '.perform_in_the_future' do + it 'schedules a job in the future' do + expect(described_class) + .to receive(:perform_in) + .with(5.minutes.to_i, 10, '123') + + described_class.perform_in_the_future(10, '123') + end + end + + describe '#perform' do + let_it_be(:project) { create(:project) } + let(:import_state) { create(:import_state, project: project, jid: '123abc', status: :started) } + + context 'when the project does not exist' do + let(:job_args) { [-1, '123'] } + + it_behaves_like 'an idempotent worker' + + it 'does nothing' do + expect(Gitlab::SidekiqStatus) + .not_to receive(:expire) + + worker.perform(*job_args) + end + end + + context 'when the job is running' do + let(:job_args) { [project.id, '123'] } + + before do + allow(Gitlab::SidekiqStatus) + .to receive(:running?) + .with('123') + .and_return(true) + end + + it_behaves_like 'an idempotent worker' + + it 'refreshes the import JID and reschedules itself' do + expect(Gitlab::SidekiqStatus) + .to receive(:expire) + .with('123', Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION) + + expect(Gitlab::SidekiqStatus) + .to receive(:set) + .with(import_state.jid, Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION) + + expect(worker.class) + .to receive(:perform_in_the_future) + .with(project.id, '123') + + worker.perform(*job_args) + end + end + + context 'when the job is no longer running' do + let(:job_args) { [project.id, '123'] } + + before do + allow(Gitlab::SidekiqStatus) + .to receive(:running?) + .with('123') + .and_return(false) + end + + it_behaves_like 'an idempotent worker' + + it 'returns' do + expect(Gitlab::SidekiqStatus) + .not_to receive(:expire) + + expect(Gitlab::SidekiqStatus) + .not_to receive(:set) + + worker.perform(*job_args) + end + end + end +end -- GitLab