Geo: Replicate Projects::Topic uploads (project_topic_uploads)
What does this MR do and why?
Adds Geo SSF (self-service framework) replication and verification for the project_topic_uploads partition table so Projects::Topic attachments (topic avatars) are mirrored from the primary to secondary Geo sites alongside the other upload partitions.
Generated with scripts/geo/generate-blob-replicator:
scripts/geo/generate-blob-replicator \
--replicable-name=project_topic_upload \
--model-class='Projects::Topic' \
--table-name=project_topic_uploads \
--sharding-key=organization_id \
--milestone=19.1 \
--upload-partition \
--parent-factory=topicThree minor cleanups were made on top of the generated output:
- Registry template whitespace. Removed trailing whitespace and extra blank line in
Geo::ProjectTopicUploadRegistry(known template hygiene issue tracked in !234804 (merged)). - Migration line breaks. Broke
add_concurrent_foreign_keylines in the states migration and the registry index line to stay within the 120-character RuboCop limit. - RuboCop alignment. Auto-corrected spacing in the registries shared context.
Selective sync uses the organization-only scope (parity with Geo::VulnerabilityExportUpload), since project_topic_uploads is sharded by organization_id only.
References
- Relates to #589917 (closed)
- Parent epic: &20933
How to set up and validate locally
Requires a primary + secondary Geo setup (e.g. two GDKs).
-
On both sites, run migrations:
bin/rake db:migrate db:migrate:geo -
On the primary, enable the feature flag:
Feature.enable(:geo_project_topic_upload_replication) -
Create a
Projects::Topicwith an avatar (Admin > Topics > New topic, attach an image). -
On the secondary, confirm the registry row was created and replication + verification succeeded:
Geo::ProjectTopicUploadRegistry.last # => state: 'synced', verification_state: 'succeeded' -
Confirm the file is present at the secondary's upload path and that
verification_checksummatches the primary's. -
Optionally spot-check the GraphQL API:
{ geoNode(name: "<secondary-name>") { projectTopicUploadRegistries { nodes { id state } } } }