From 7a2b2e02bf363dd763f9c0a736f067c59dd9f24b Mon Sep 17 00:00:00 2001 From: Ian Baum Date: Fri, 12 Dec 2025 16:05:09 -0600 Subject: [PATCH] POC for tracking oldest unsynced object on a secondary --- ee/app/models/concerns/geo/replicable_registry.rb | 7 +++++++ ee/app/models/geo_node_status.rb | 3 ++- ee/lib/gitlab/geo/replicator.rb | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ee/app/models/concerns/geo/replicable_registry.rb b/ee/app/models/concerns/geo/replicable_registry.rb index ddb7eaeacb0b41..df2557022858df 100644 --- a/ee/app/models/concerns/geo/replicable_registry.rb +++ b/ee/app/models/concerns/geo/replicable_registry.rb @@ -19,6 +19,12 @@ def state_value(state_string) STATE_VALUES[state_string] end + def unsynced_objects + # rubocop:disable Database/AvoidUsingPluckWithoutLimit -- To be fixed before merge + model_class.find(unsynced.pluck(model_foreign_key)).minimum(:updated_at) + # rubocop:enable Database/AvoidUsingPluckWithoutLimit + end + def for_model_record_id(id) find_or_initialize_by(model_foreign_key => id) end @@ -81,6 +87,7 @@ def replicator_class scope :retry_due, -> { where(arel_table[:retry_at].eq(nil).or(arel_table[:retry_at].lt(Time.current))) } scope :synced, -> { with_state(:synced) } scope :sync_timed_out, -> { with_state(:started).where(last_synced_at: ...replicator_class.sync_timeout.ago) } + scope :unsynced, -> { without_state(:synced) } state_machine :state, initial: :pending do state :pending, value: STATE_VALUES[:pending] diff --git a/ee/app/models/geo_node_status.rb b/ee/app/models/geo_node_status.rb index 530a07f9d9a951..7b4fa8a1c53deb 100644 --- a/ee/app/models/geo_node_status.rb +++ b/ee/app/models/geo_node_status.rb @@ -36,7 +36,8 @@ def self.status_fields_for(replicable_class) "#{replicable_class.replicable_name_plural}_registry_count": "Number of #{replicable_class.replicable_title_plural} synced to sync on secondary", "#{replicable_class.replicable_name_plural}_verification_total_count": "Number of #{replicable_class.replicable_title_plural} available to verify on secondary", "#{replicable_class.replicable_name_plural}_verified_count": "Number of #{replicable_class.replicable_title_plural} verified on the secondary", - "#{replicable_class.replicable_name_plural}_verification_failed_count": "Number of #{replicable_class.replicable_title_plural} failed to verify on secondary" + "#{replicable_class.replicable_name_plural}_verification_failed_count": "Number of #{replicable_class.replicable_title_plural} failed to verify on secondary", + "#{replicable_class.replicable_name_plural}_oldest_unsynced_time": "Timestamp of the oldest out of sync #{replicable_class.replicable_title_plural} on secondary" } end diff --git a/ee/lib/gitlab/geo/replicator.rb b/ee/lib/gitlab/geo/replicator.rb index 1a83864f4194eb..d02f8ae8be6405 100644 --- a/ee/lib/gitlab/geo/replicator.rb +++ b/ee/lib/gitlab/geo/replicator.rb @@ -175,6 +175,10 @@ def self.replication_enabled? Feature.enabled?(replication_enabled_feature_key, type: :ops) end + def self.oldest_unsynced + registry_class.with_state(:synced) + end + # @example Given `Geo::PackageFileRegistryFinder`, this returns # `::Geo::PackageFileReplicator` # @example Given `Resolver::Geo::PackageFileRegistriesResolver`, this -- GitLab