[go: up one dir, main page]

Skip to content

Set importing on objects through global context

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

About

There are often validations and callbacks on models that should be switched off during an import. See example validation and example callback.

We do this:

Problem

To disable callbacks on an object we create during an import, we must always remember to set importing: true on the object before saving, if that object's class includes the Importable module.

We often forget to set importing: true on all objects before we save them.

So the current method is error-prone and brittle.

Some problems when we forget to set this property:

This seems to be extensive, examples spotted in just github_import/importer/events are:

Proposal

Globals are an anti-pattern, but I think we could:

  • Implement a controlled form of a global where we set state within Gitlab::SafeRequestStore once. This is available to Sidekiq workers.
  • This would be read by the Importable module to know that we're importing.

So we would "set and forget".

Example code

Just to sketch out the proposal in code:

Click to see semi-pseudo code

Semi-pseudo code (untested):

module Import
  # Wrap the importing code in a block that ensured the state flag was unset
  def importing(&block)
    Gitlab::SafeRequestStore[:importing] = true
    yield
  ensure
    Gitlab::SafeRequestStore.delete(:importing)
  end

  # From Sidekiq, generally a worker will always be creating import data,
  # so we could probably just set it without needing to unset it
  def importing!
    raise "..." unless Gitlab::Runtime.sidekiq?

    Gitlab::SafeRequestStore[:importing] = true
  end
end

Importable module would be rewritten:

diff --git a/app/models/concerns/importable.rb b/app/models/concerns/importable.rb
index 4d2707b08abd..1ccc432e9820 100644
--- a/app/models/concerns/importable.rb
+++ b/app/models/concerns/importable.rb
@@ -4,8 +4,11 @@ module Importable
   extend ActiveSupport::Concern

   attr_accessor :importing
-  alias_method :importing?, :importing

   attr_accessor :imported
   alias_method :imported?, :imported
+
+  def importing?
+    Gitlab::SafeRequestStore[:importing] || importing
+  end
 end

And we would use it like this:

# Rails/rake task:
Import.importing do
  # ... create the import data
end

# Otherwise, from Sidekiq, generally a worker will always be creating 
# import data, so we could probably just set it within `#perform` so it's
# not part of every stack trace.
# We can block non-Sidekiq context code from being able to use this method.
Import.importing!
# ... create the import data
Edited by 🤖 GitLab Bot 🤖