Geo: Replicate DesignManagement::Action uploads

What does this MR do and why?

This code change adds support for replicating and verifying design management action uploads in GitLab's Geo feature (which keeps multiple GitLab instances synchronized).

The changes create a new database table to track the synchronization status of design files uploaded through GitLab's design management system. This includes adding verification states to ensure files are properly copied between different GitLab servers, along with checksums to verify file integrity.

The update also adds new monitoring metrics so administrators can track how many design uploads have been successfully synchronized, failed, or are pending verification across their GitLab instances. Additionally, it updates the API documentation to include these new design upload statistics in the Geo status reports.

This enhancement ensures that design files uploaded to GitLab projects are properly backed up and synchronized across multiple GitLab installations for disaster recovery and performance purposes.

References

Related to #589909 (closed)

How to set up and validate locally

Prerequisites

1. Run database migrations

rails db:migrate # on the primary
rails db:migrate:geo # on the secondary

2. Enable the feature flags on the primary

# In Rails console on the primary
Feature.enable(:geo_design_management_action_upload_replication)
Feature.enable(:geo_design_management_action_upload_force_primary_checksumming)

3. Create test data on the primary

Upload a design to a project issue (e.g., attach an image via the Design Management tab on an issue). Alternatively, use the Rails console:

# In Rails console on the primary
user = User.admins.first
project = Project.first
issue = project.issues.first || Issues::CreateService.new(
  container: project,
  current_user: user,
  params: { title: 'Test issue for designs' }
).execute[:issue]

# Upload a design image (must be PNG, JPEG, BMP, or GIF for thumbnail generation)
file = ActionDispatch::Http::UploadedFile.new(
  tempfile: File.open(Rails.root.join('spec/fixtures/dk.png')),
  filename: 'dk.png',
  content_type: 'image/png'
)

result = DesignManagement::SaveDesignsService.new(project, user, issue: issue, files: [file]).execute
version = result[:version]

# Generate the image_v432x230 thumbnail upload on DesignManagement::Action
# This is what creates the Upload record in the design_management_action_uploads partition
DesignManagement::GenerateImageVersionsService.new(version).execute

Verify the upload exists in the design_management_action_uploads partition:

Geo::DesignManagementActionUpload.count
# Should be > 0

4. Verify checksumming on the primary

Wait for the verification worker to process, or trigger it manually:

# In Rails console on the primary
Geo::DesignManagementActionUpload.first.replicator.verify
Geo::DesignManagementActionUpload.first.design_management_action_upload_state.reload
Geo::DesignManagementActionUpload.first.design_management_action_upload_state.verification_state
# Should be 2 (verification_succeeded)

5. Verify replication on the secondary

Once the upload is created on the primary, Geo will automatically replicate it to the secondary. Check the sync status in the secondary Rails console:

# In Rails console on the secondary
Geo::DesignManagementActionUploadRegistry.count
# Should be > 0

registry = Geo::DesignManagementActionUploadRegistry.last
registry.state
# Should be 2 (synced)

If the registry is empty or not yet synced, you can manually trigger sync:

# In Rails console on the secondary
Geo::DesignManagementActionUploadReplicator.new(model_record_id: Geo::DesignManagementActionUpload.first.id).sync

6. Verify verification on the secondary

# In Rails console on the secondary
registry = Geo::DesignManagementActionUploadRegistry.last
registry.reload
registry.verification_state
# Should be 2 (verification_succeeded)

7. Test GraphQL API on the secondary

Note: You must be logged in as an admin user. Non-admin users will get null for Geo-related queries.

Note: When querying from the secondary's GraphQL explorer, add a custom header REQUEST_PATH with the value `/api/v4/geo/node_proxy/{node_id}/graphql

Open the GraphQL explorer on the secondary instance (http://<secondary-url>/-/graphql-explorer) and run:

query {
  geoNode {
    name
    primary
    designManagementActionUploadRegistries {
      nodes {
        id
        state
        verificationState
        designManagementActionUploadId
        lastSyncedAt
        verifiedAt
      }
    }
  }
}

Expected result: you should see registry entries with state: "SYNCED" and verificationState: "VERIFIED".

8. Verify Geo Sites API

Check the Geo Sites API includes the new design management action upload statistics:

curl --header "PRIVATE-TOKEN: <your-token>" "http://<primary-url>/api/v4/geo_sites/status"

Look for the new fields in the response:

  • design_management_action_uploads_count
  • design_management_action_uploads_checksummed_count
  • design_management_action_uploads_checksum_failed_count
  • design_management_action_uploads_synced_count
  • design_management_action_uploads_failed_count
  • design_management_action_uploads_registry_count
  • design_management_action_uploads_synced_in_percentage
  • design_management_action_uploads_verified_in_percentage

9. Verify Geo admin page

Visit /admin/geo/sites on the secondary and confirm that "Design Management Action Uploads" appears as a new data type with replication and verification progress.

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.

Edited by Douglas Barbosa Alexandre

Merge request reports

Loading