summaryrefslogtreecommitdiff
path: root/lib/gitlab/background_migration/backfill_project_namespace_on_issues.rb
blob: 34dd3321125885ad1d014a871481bcda48507273 (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
# frozen_string_literal: true

module Gitlab
  module BackgroundMigration
    # Back-fills the `issues.namespace_id` by setting it to corresponding project.project_namespace_id
    class BackfillProjectNamespaceOnIssues < BatchedMigrationJob
      MAX_UPDATE_RETRIES = 3

      operation_name :update_all

      def perform
        each_sub_batch(
          batching_scope: -> (relation) {
            relation.joins("INNER JOIN projects ON projects.id = issues.project_id")
              .select("issues.id AS issue_id, projects.project_namespace_id").where(issues: { namespace_id: nil })
          }
        ) do |sub_batch|
          # updating issues table results in failed batches quite a bit,
          # to prevent that as much as possible we try to update the same sub-batch up to 3 times.
          update_with_retry(sub_batch)
        end
      end

      private

      # rubocop:disable Database/RescueQueryCanceled
      # rubocop:disable Database/RescueStatementTimeout
      def update_with_retry(sub_batch)
        update_attempt = 1

        begin
          update_batch(sub_batch)
        rescue ActiveRecord::StatementTimeout, ActiveRecord::QueryCanceled => e
          update_attempt += 1

          if update_attempt <= MAX_UPDATE_RETRIES
            sleep(5)
            retry
          end

          raise e
        end
      end
      # rubocop:enable Database/RescueQueryCanceled
      # rubocop:enable Database/RescueStatementTimeout

      def update_batch(sub_batch)
        connection.execute <<~SQL
            UPDATE issues
            SET namespace_id = projects.project_namespace_id
            FROM (#{sub_batch.to_sql}) AS projects(issue_id, project_namespace_id)
            WHERE issues.id = issue_id
        SQL
      end
    end
  end
end