summaryrefslogtreecommitdiff
path: root/lib/gitlab/import_export/project/import_task.rb
blob: 4ea47a5624aa8aef78a32613dc5266e64b543a66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# frozen_string_literal: true

module Gitlab
  module ImportExport
    module Project
      class ImportTask < BaseTask
        def import
          show_import_start_message

          run_isolated_sidekiq_job

          show_import_failures_count

          return error(project.import_state.last_error) if project.import_state&.last_error
          return error(project.errors.full_messages.to_sentence) if project.errors.any?

          success('Done!')
        end

        private

        # We want to ensure that all Sidekiq jobs are executed
        # synchronously as part of that process.
        # This ensures that all expensive operations do not escape
        # to general Sidekiq clusters/nodes.
        def with_isolated_sidekiq_job
          Sidekiq::Testing.fake! do
            with_request_store do
              # If you are attempting to import a large project into a development environment,
              # you may see Gitaly throw an error about too many calls or invocations.
              # This is due to a n+1 calls limit being set for development setups (not enforced in production)
              # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24475#note_283090635
              # For development setups, this code-path will be excluded from n+1 detection.
              ::Gitlab::GitalyClient.allow_n_plus_1_calls do
                yield
              end
            end

            true
          end
        end

        def run_isolated_sidekiq_job
          with_isolated_sidekiq_job do
            @project = create_project

            execute_sidekiq_job
          end
        end

        def create_project
          # We are disabling ObjectStorage for `import`
          # as it is too slow to handle big archives:
          # 1. DB transaction timeouts on upload
          # 2. Download of archive before unpacking
          disable_upload_object_storage do
            service = Projects::GitlabProjectsImportService.new(
              current_user,
              import_params
            )

            service.execute
          end
        end

        def execute_sidekiq_job
          Sidekiq::Worker.drain_all # rubocop:disable Cop/SidekiqApiUsage
        end

        def full_path
          "#{namespace.full_path}/#{project_path}"
        end

        def show_import_start_message
          logger.info "Importing GitLab export: #{file_path} into GitLab" \
            " #{full_path}" \
            " as #{current_user.name}"
        end

        def import_params
          {
            namespace_id: namespace.id,
            path: project_path,
            file: File.open(file_path)
          }
        end

        def show_import_failures_count
          return unless project.import_failures.exists?

          logger.info "Total number of not imported relations: #{project.import_failures.count}"
        end
      end
    end
  end
end