Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/services/users/destroy_service.rb')
-rw-r--r--app/services/users/destroy_service.rb65
1 files changed, 42 insertions, 23 deletions
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb
index a378cb09854..d4c00a4dcec 100644
--- a/app/services/users/destroy_service.rb
+++ b/app/services/users/destroy_service.rb
@@ -8,9 +8,20 @@ module Users
def initialize(current_user)
@current_user = current_user
+
+ @scheduled_records_gauge = Gitlab::Metrics.gauge(
+ :gitlab_ghost_user_migration_scheduled_records_total,
+ 'The total number of scheduled ghost user migrations'
+ )
+ @lag_gauge = Gitlab::Metrics.gauge(
+ :gitlab_ghost_user_migration_lag_seconds,
+ 'The waiting time in seconds of the oldest scheduled record for ghost user migration'
+ )
end
- # Synchronously destroys +user+
+ # Asynchronously destroys +user+
+ # Migrating the associated user records, and post-migration cleanup is
+ # handled by the Users::MigrateRecordsToGhostUserWorker cron worker.
#
# The operation will fail if the user is the sole owner of any groups. To
# force the groups to be destroyed, pass `delete_solo_owned_groups: true` in
@@ -24,10 +35,7 @@ module Users
# a hard deletion without destroying solo-owned groups, pass
# `delete_solo_owned_groups: false, hard_delete: true` in +options+.
#
- # To make the service asynchronous, a new behaviour is being introduced
- # behind the user_destroy_with_limited_execution_time_worker feature flag.
- # Migrating the associated user records, and post-migration cleanup is
- # handled by the Users::MigrateRecordsToGhostUserWorker cron worker.
+
def execute(user, options = {})
delete_solo_owned_groups = options.fetch(:delete_solo_owned_groups, options[:hard_delete])
@@ -62,32 +70,43 @@ module Users
yield(user) if block_given?
hard_delete = options.fetch(:hard_delete, false)
+ Users::GhostUserMigration.create!(user: user,
+ initiator_user: current_user,
+ hard_delete: hard_delete)
- if Feature.enabled?(:user_destroy_with_limited_execution_time_worker)
- Users::GhostUserMigration.create!(user: user,
- initiator_user: current_user,
- hard_delete: hard_delete)
+ update_metrics
+ end
- else
- MigrateToGhostUserService.new(user).execute(hard_delete: options[:hard_delete])
+ private
+
+ attr_reader :scheduled_records_gauge, :lag_gauge
- response = Snippets::BulkDestroyService.new(current_user, user.snippets)
- .execute(skip_authorization: hard_delete)
- raise DestroyError, response.message if response.error?
+ def update_metrics
+ update_scheduled_records_gauge
+ update_lag_gauge
+ end
- # Rails attempts to load all related records into memory before
- # destroying: https://github.com/rails/rails/issues/22510
- # This ensures we delete records in batches.
- user.destroy_dependent_associations_in_batches(exclude: [:snippets])
- user.nullify_dependent_associations_in_batches
+ def update_scheduled_records_gauge
+ # We do not want to issue unbounded COUNT() queries, hence we limit the
+ # query to count 1001 records and then approximate the result.
+ count = Users::GhostUserMigration.limit(1001).count
- # Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
- user_data = user.destroy
- namespace.destroy
+ if count == 1001
+ # more than 1000 records, approximate count
+ min = Users::GhostUserMigration.minimum(:id) || 0
+ max = Users::GhostUserMigration.maximum(:id) || 0
- user_data
+ scheduled_records_gauge.set({}, max - min)
+ else
+ # less than 1000 records, count is accurate
+ scheduled_records_gauge.set({}, count)
end
end
+
+ def update_lag_gauge
+ oldest_job = Users::GhostUserMigration.first
+ lag_gauge.set({}, Time.current - oldest_job.created_at)
+ end
end
end