1# frozen_string_literal: true 2 3class ProjectImportState < ApplicationRecord 4 include AfterCommitQueue 5 include ImportState::SidekiqJobTracker 6 7 self.table_name = "project_mirror_data" 8 9 belongs_to :project, inverse_of: :import_state 10 11 validates :project, presence: true 12 13 alias_attribute :correlation_id, :correlation_id_value 14 15 state_machine :status, initial: :none do 16 event :schedule do 17 transition [:none, :finished, :failed] => :scheduled 18 end 19 20 event :force_start do 21 transition [:none, :finished, :failed] => :started 22 end 23 24 event :start do 25 transition scheduled: :started 26 end 27 28 event :finish do 29 transition started: :finished 30 end 31 32 event :fail_op do 33 transition [:scheduled, :started] => :failed 34 end 35 36 state :scheduled 37 state :started 38 state :finished 39 state :failed 40 41 after_transition [:none, :finished, :failed] => :scheduled do |state, _| 42 state.run_after_commit do 43 job_id = project.add_import_job 44 45 if job_id 46 correlation_id = Labkit::Correlation::CorrelationId.current_or_new_id 47 update(jid: job_id, correlation_id_value: correlation_id) 48 end 49 end 50 end 51 52 after_transition any => :finished do |state, _| 53 if state.jid.present? 54 Gitlab::SidekiqStatus.unset(state.jid) 55 56 state.update_column(:jid, nil) 57 end 58 end 59 60 after_transition started: :finished do |state, _| 61 project = state.project 62 63 project.reset_cache_and_import_attrs 64 65 if Gitlab::ImportSources.importer_names.include?(project.import_type) && project.repo_exists? 66 # rubocop: disable CodeReuse/ServiceClass 67 state.run_after_commit do 68 Projects::AfterImportService.new(project).execute 69 end 70 # rubocop: enable CodeReuse/ServiceClass 71 end 72 end 73 end 74 75 def relation_hard_failures(limit:) 76 project.import_failures.hard_failures_by_correlation_id(correlation_id).limit(limit) 77 end 78 79 def mark_as_failed(error_message) 80 original_errors = errors.dup 81 sanitized_message = Gitlab::UrlSanitizer.sanitize(error_message) 82 83 fail_op 84 85 update_column(:last_error, sanitized_message) 86 rescue ActiveRecord::ActiveRecordError => e 87 Gitlab::Import::Logger.error( 88 message: 'Error setting import status to failed', 89 error: e.message, 90 original_error: sanitized_message 91 ) 92 ensure 93 @errors = original_errors 94 end 95 96 alias_method :no_import?, :none? 97 98 def in_progress? 99 scheduled? || started? 100 end 101 102 def started? 103 # import? does SQL work so only run it if it looks like there's an import running 104 status == 'started' && project.import? 105 end 106end 107 108ProjectImportState.prepend_mod_with('ProjectImportState') 109