DeleteUserService#execute deletes the user before deleting its projects so projects deletion fail
In DeleteUserService#execute
we schedule a user's projects deletion and then we delete the user:
def execute(user, options = {})
if !options[:delete_solo_owned_groups] && user.solo_owned_groups.present?
user.errors[:base] << 'You must transfer ownership or delete groups before you can remove user'
return user
end
user.solo_owned_groups.each do |group|
DestroyGroupService.new(group, current_user).execute
end
user.personal_projects.each do |project|
# Skip repository removal because we remove directory with namespace
# that contain all this repositories
::Projects::DestroyService.new(project, current_user, skip_repo: true).async_execute
end
# Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
namespace = user.namespace
user_data = user.destroy
namespace.really_destroy!
user_data
end
The issue is that DestroyProjectWorker
needs the user in order to delete its project!
def perform(project_id, user_id, params)
begin
project = Project.unscoped.find(project_id)
rescue ActiveRecord::RecordNotFound
return
end
user = User.find(user_id)
::Projects::DestroyService.new(project, user, params.symbolize_keys).execute
end
/cc @stanhu @DouweM @smcgivern This can probably explain a lot of the soft-deleted projects we currently have (see #20984 (closed)), even thought there are probably multiple causes...
I've checked in production and there are indeed failed ProjectDestroyWorker
jobs due to ActiveRecord::RecordNotFound: Couldn't find User with 'id'=XXXXX
!