Skip to content

Allow nesting of SharedModel.using_connection

What does this MR do and why?

Related to #343047 (closed)

Allow SharedModel.using_connection blocks to be nested as long as they use the same connection object. This is useful for making background migrations compatible with multiple databases, because we have several entry points and we want to ensure the shared connection is setup properly in each.

We can imagine that happening in code like this:

class BackgroundMigrationWorker
  def perform(class_name, args)
    Gitlab::Database::SharedModel.using_connection(connection) do
      # other operations using a SharedModel

      Gitlab::BackgroundMigration.perform(class_name, *rgs)
    end
  end
end

module Gitlab
  module BackgroundMigration
    def self.perform(class_name, args)
      Gitlab::Database::SharedModel.using_connection(connection) do
        class_name.constantize.new.perform(*args)
      end
    end
  end
end

We prefer to always setup the shared connection at the outermost level possible, so that future code changes are guaranteed to have the right connection. Sidekiq enters into running the job through BackgroundMigrationWorker#perform, but other code may call BackgroundMigration.perform directly. Typically we don't call this code directly outside of a migration context, but we want to guard against unexpected calls with the wrong connection.

We also still want to prevent setting multiple nested levels with different connections, since that seems unnecessary at this time and likely indicates something in our connection-handling logic is wrong.

How to set up and validate locally

The added test cases can be tried locally to verify that it works. Note that nested objects must be the same object, not just equivalent objects.

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Patrick Bair

Merge request reports