Skip to content

SharedModel.using_connection doesn't override connection_db_config

Summary

When used within SharedModel.using_connection, connection_db_config still returns the original connection database config, and not the one for the overriding connection.

This leads to incorrect lease keys generated, for example in https://gitlab.com/gitlab-org/gitlab/-/blob/caf64fec980ce1161226e88142da735d3048eb59/lib/gitlab/database/reindexing/coordinator.rb#L77.

Here are all usages of connection_db_config as of now:

$ git grep --line-number "connection_db_config.name"
lib/gitlab/database.rb:52:    PRIMARY_DATABASE_NAME = ActiveRecord::Base.connection_db_config.name.to_sym # rubocop:disable Database/MultipleDatabases
lib/gitlab/database/async_indexes/index_creator.rb:51:          [super, async_index.connection_db_config.name].join('/')
lib/gitlab/database/async_indexes/index_destructor.rb:57:          [super, async_index.connection_db_config.name].join('/')
lib/gitlab/database/count/reltuples_count_strategy.rb:60:          models.group_by { |model| model.connection_db_config.name }.map do |db_name, models_for_db|
lib/gitlab/database/each_database.rb:64:          connection_name = model.connection_db_config.name
lib/gitlab/database/load_balancing/configuration.rb:66:          @model.connection_db_config.name.to_sym
lib/gitlab/database/partitioning.rb:41:                if connection_name != model.connection_db_config.name
lib/gitlab/database/reindexing/coordinator.rb:77:          [super, index.connection_db_config.name].join('/')
lib/gitlab/metrics/samplers/database_sampler.rb:67:            db_config_name: klass.connection_db_config.name
spec/lib/gitlab/database/each_database_spec.rb:132:        allow(main_model).to receive_message_chain('connection_db_config.name').and_return('main')
spec/lib/gitlab/database/each_database_spec.rb:133:        allow(ci_model).to receive_message_chain('connection_db_config.name').and_return('ci')
spec/lib/gitlab/database/each_database_spec.rb:154:        allow(main_model).to receive_message_chain('connection_db_config.name').and_return('main')
spec/lib/gitlab/database/each_database_spec.rb:155:        allow(ci_model).to receive_message_chain('connection_db_config.name').and_return('ci')
spec/support/db_cleaner.rb:50:      puts "The #{result['table']} (#{connection_class.connection_db_config.name}) table has #{result['column_count']} columns."

Steps to reproduce

Gitlab::Database::SharedModel.using_connection(Ci::ApplicationRecord.connection) do
  index = Gitlab::Database::Reindexing::QueuedAction.last.index
  
  puts "Current database: #{index.connection.execute('select current_database()').to_a[0]['current_database']}"
  puts "Index connection name: #{index.connection_db_config.name}" # <-- should be `ci`, but is `main`

  config = Gitlab::Database.db_config_for_connection(index.connection)
  puts "Config for connection name: #{config.name}" # <-- correctly returns `ci`
end

What is the current bug behavior?

When used within using_connection, connection_db_config still returns the original connection config.

What is the expected correct behavior?

It should return the overriding connection config.

Possible fixes

Short term we can replace all usage with Gitlab::Database.db_config_for_connection(index.connection).name.

Long term we may change using_connection to override the database config too.

Use native AR multiple database support for Git... (#352333) is related too.