Commit 7d633be8 authored by Vasilii Iakliushin's avatar Vasilii Iakliushin

Delete events in batches when project is destroyed

Contributes to https://gitlab.com/gitlab-org/gitlab/-/issues/346169

**Problem**

The previous attempt to extract delete events query from project
delete did not help to resolve the statement timeout problem.

**Solution**

Use batch delete for events.

Changelog: changed
parent fbc64cb4
...@@ -2,20 +2,29 @@ ...@@ -2,20 +2,29 @@
module Events module Events
class DestroyService class DestroyService
BATCH_SIZE = 50
def initialize(project) def initialize(project)
@project = project @project = project
end end
def execute def execute
project.events.all.delete_all loop do
count = delete_events_in_batches
break if count < BATCH_SIZE
end
ServiceResponse.success(message: 'Events were deleted.') ServiceResponse.success(message: 'Events were deleted.')
rescue StandardError rescue StandardError => e
ServiceResponse.error(message: 'Failed to remove events.') ServiceResponse.error(message: e.message)
end end
private private
attr_reader :project attr_reader :project
def delete_events_in_batches
project.events.limit(BATCH_SIZE).delete_all
end
end end
end end
...@@ -80,8 +80,14 @@ module Projects ...@@ -80,8 +80,14 @@ module Projects
end end
def remove_events def remove_events
log_info("Attempting to destroy events from #{project.full_path} (#{project.id})")
response = ::Events::DestroyService.new(project).execute response = ::Events::DestroyService.new(project).execute
if response.error?
log_error("Event deletion failed on #{project.full_path} with the following message: #{response.message}")
end
response.success? response.success?
end end
......
...@@ -30,16 +30,28 @@ RSpec.describe Events::DestroyService do ...@@ -30,16 +30,28 @@ RSpec.describe Events::DestroyService do
expect(unrelated_event.reload).to be_present expect(unrelated_event.reload).to be_present
end end
context 'batch delete' do
before do
stub_const("#{described_class}::BATCH_SIZE", 2)
end
it 'splits delete queries into batches' do
expect(project).to receive(:events).twice.and_call_original
subject.execute
end
end
context 'when an error is raised while deleting the records' do context 'when an error is raised while deleting the records' do
before do before do
allow(project).to receive_message_chain(:events, :all, :delete_all).and_raise(ActiveRecord::ActiveRecordError) allow(project).to receive_message_chain(:events, :limit, :delete_all).and_raise(ActiveRecord::ActiveRecordError, 'custom error')
end end
it 'returns error' do it 'returns error' do
response = subject.execute response = subject.execute
expect(response).to be_error expect(response).to be_error
expect(response.message).to eq 'Failed to remove events.' expect(response.message).to eq 'custom error'
end end
it 'does not delete events' do it 'does not delete events' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment