Persist reassignment error to source users on failure

What does this MR do and why?

Previously, when a source user failed reassignment, the failure's exception message was logged to importer.log but not persisted to the reassignment_error column on the source user record, even though the column exists and is already on ImportSourceUser GraphQL objects. This MR updates Import::ReassignPlaceholderUserRecordsWorker to truncate and save the failure exception so that it can be returned when querying for source users in the API. This change will support implementing retrying failed placeholder reassignments.

References

Screenshots or screen recordings

The UI was technically already displaying the error message on the placeholder user table, but it was never visible because we never persisted it:

image

How to set up and validate locally

  1. Find or create an import source user (placeholder user) by running an import from any of the supported importers. Do not import a project into a personal namespace because it will assign all contributions directly to the personal namespace's user.
  2. Once the import finishes, update Import::ReassignPlaceholderUserRecordsWorker to raise an error. Otherwise, you're unlikely to get the reassignment to fail. Something like:
diff --git a/app/workers/import/reassign_placeholder_user_records_worker.rb b/app/workers/import/reassign_placeholder_user_records_worker.rb
index 0004fbc1c95e24..f6e64c64861b32 100644
--- a/app/workers/import/reassign_placeholder_user_records_worker.rb
+++ b/app/workers/import/reassign_placeholder_user_records_worker.rb
@@ -11,7 +11,7 @@ class ReassignPlaceholderUserRecordsWorker
     data_consistency :sticky
     feature_category :importers
     deduplicate :until_executed
-    sidekiq_options retry: 5, dead: false
+    sidekiq_options retry: 1, dead: false
     sidekiq_options max_retries_after_interruption: 20
     concurrency_limit -> { 4 }
 
@@ -20,6 +20,8 @@ class ReassignPlaceholderUserRecordsWorker
     end
 
     def perform(import_source_user_id, params = {})
+      raise StandardError, 'PG::QueryCanceled: ERROR: canceling statement due to statement timeout'
+
       @import_source_user = Import::SourceUser.find_by_id(import_source_user_id)
       return unless import_source_user_valid?
  1. Navigate to the import's top-level group's membership page, then to the "placeholders" tab, and assign a placeholder user to a real user. Then, accept the assignment (this can be done by impersonating the real assigned user, opening the reassignment notification email, and accepting).
  2. Accepting the reassignment begins the backend process to reassign all imported records to the real user. The exception added in step 2 should be thrown and cause the reassignment to fail. Allow the async worker to finish.
  3. Using GraphQL, query for the ImportSourceUser that just failed. Validate reassignmentError matches the message thrown in step 2.
  4. Verify that the reassignment error is also now visible in the UI

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #589777

Edited by Sam Word

Merge request reports

Loading