Skip to content
Snippets Groups Projects
Verified Commit 71659cf7 authored by Adam Hegyi's avatar Adam Hegyi Committed by GitLab
Browse files

Merge branch '502407-backfill-user-details' into 'master'

Backfill missing user_detail records for specific user_types

See merge request !174064



Merged-by: Adam Hegyi's avatarAdam Hegyi <ahegyi@gitlab.com>
Approved-by: default avatarJoão Pereira <jpereira@gitlab.com>
Approved-by: Adam Hegyi's avatarAdam Hegyi <ahegyi@gitlab.com>
Reviewed-by: Doug Stull's avatarDoug Stull <dstull@gitlab.com>
Co-authored-by: Doug Stull's avatarDoug Stull <dstull@gitlab.com>
parents 6ca87d3f db133ec6
No related branches found
No related tags found
1 merge request!174064Backfill missing user_detail records for specific user_types
Pipeline #1569558306 passed with warnings
Pipeline: E2E CNG

#1569593923

    Pipeline: E2E Omnibus GitLab EE

    #1569593921

      Pipeline: E2E GDK

      #1569574250

        +30
        # frozen_string_literal: true
        class BackfillUserDetails < Gitlab::Database::Migration[2.2]
        milestone '17.7'
        restrict_gitlab_migration gitlab_schema: :gitlab_main
        disable_ddl_transaction!
        BATCH_SIZE = 50
        USER_TYPES = [15, 17] # 15: placeholder, 17: import_user
        class UserDetail < MigrationRecord
        self.table_name = :user_details
        end
        def up
        process_users_in_batches
        end
        def down; end
        private
        def process_users_in_batches
        users_model = define_batchable_model('users')
        USER_TYPES.each do |user_type|
        users_model.where(user_type: user_type).each_batch(of: BATCH_SIZE) do |batch|
        user_ids = find_users_without_details(batch)
        next if user_ids.empty?
        create_user_details(user_ids)
        end
        end
        end
        def find_users_without_details(batch)
        batch
        .joins('LEFT JOIN user_details ON (users.id = user_details.user_id)')
        .where(user_details: { user_id: nil })
        .ids
        end
        def create_user_details(user_ids)
        attributes = build_user_details_attributes(user_ids)
        safely_insert_user_details(attributes, user_ids)
        end
        def build_user_details_attributes(user_ids)
        user_ids.map { |user_id| { user_id: user_id } }
        end
        def safely_insert_user_details(attributes, user_ids)
        UserDetail.upsert_all(attributes, returning: false)
        rescue Exception => e # rubocop:disable Lint/RescueException -- following https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#best-practices re-raise
        log_error(e, user_ids)
        raise
        end
        def log_error(error, user_ids)
        logger.error(
        class: error.class,
        message: "BackfillUserDetails Migration: error inserting. Reason: #{error.message}",
        user_ids: user_ids
        )
        end
        def logger
        @logger ||= Gitlab::BackgroundMigration::Logger.build
        end
        end
        46f14b1087e567fc362949a1a4cb844868204266439a1663c1bd76879afcb9b5
        \ No newline at end of file
        # frozen_string_literal: true
        require 'spec_helper'
        require_migration!
        RSpec.describe BackfillUserDetails, migration: :gitlab_main, feature_category: :acquisition, migration_version: 20241127210044 do
        let(:connection) { ActiveRecord::Base.connection }
        let(:users) { table(:users) }
        let(:user_details) { table(:user_details) }
        let!(:first_user) do
        users.create!(name: 'bob', email: 'bob@example.com', projects_limit: 1, user_type: 15).tap do |record|
        user_details.create!(user_id: record.id)
        end
        end
        let!(:user_without_details) { users.create!(name: 'foo', email: 'foo@example.com', projects_limit: 1, user_type: 15) }
        let!(:multiple_user_without_details) do
        users.create!(name: 'foo2', email: 'foo2@example.com', projects_limit: 1, user_type: 17)
        end
        let!(:user_without_details_out_of_scope) do
        users.create!(name: 'foo3', email: 'foo3@example.com', projects_limit: 1, user_type: 0)
        end
        describe '#up' do
        it 'creates only the needed user_details entries' do
        expect(user_details.count).to eq(1)
        expect(user_details.exists?(user_id: first_user.id)).to be(true)
        expect(user_details.exists?(user_id: user_without_details.id)).to be(false)
        expect(user_details.exists?(user_id: multiple_user_without_details.id)).to be(false)
        expect(user_details.exists?(user_id: user_without_details_out_of_scope.id)).to be(false)
        expect { migrate! }.to change { user_details.count }.by(2)
        expect(user_details.exists?(user_id: user_without_details.id)).to be(true)
        expect(user_details.exists?(user_id: multiple_user_without_details.id)).to be(true)
        expect(user_details.exists?(user_id: user_without_details_out_of_scope.id)).to be(false)
        end
        context 'when there are no user_details that are missing for user records' do
        before do
        user_details.create!(user_id: user_without_details.id)
        user_details.create!(user_id: multiple_user_without_details.id)
        user_details.create!(user_id: user_without_details_out_of_scope.id)
        end
        it 'creates only the needed user_details entries' do
        expect(user_details.count).to eq(4)
        expect { migrate! }.not_to change { user_details.count }
        end
        end
        context 'when upsert raises an error' do
        before do
        allow(described_class::UserDetail).to receive(:upsert_all).and_raise(Exception, '_error_')
        end
        it 'logs the error' do
        expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |logger|
        details = {
        class: Exception,
        message: "BackfillUserDetails Migration: error inserting. Reason: _error_",
        user_ids: [user_without_details.id]
        }
        expect(logger).to receive(:error).with(details)
        end
        expect { migrate! }.to raise_error(Exception)
        end
        end
        end
        end
        0% Loading or .
        You are about to add 0 people to the discussion. Proceed with caution.
        Finish editing this message first!
        Please register or to comment