Skip to content
This repository was archived by the owner on Oct 27, 2022. It is now read-only.

Commit a6ea0a0

Browse files
authored
Merge pull request #1041 from dmlond/DDS-922_optimize_child_deletion_job
DDS-922_optimize_child_deletion_job
2 parents 5eca8b5 + 641e313 commit a6ea0a0

File tree

6 files changed

+112
-84
lines changed

6 files changed

+112
-84
lines changed

app/jobs/child_deletion_job.rb

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
class ChildDeletionJob < ApplicationJob
22
queue_as :child_deletion
33

4-
def perform(job_transaction, parent)
4+
def perform(job_transaction, parent, page)
55
self.class.start_job(job_transaction)
6-
parent.children.each do |child|
7-
child.current_transaction = job_transaction if child.class.include? ChildMinder
8-
child.update(is_deleted: true)
9-
end
6+
parent.current_transaction = job_transaction
7+
parent.delete_children(page)
108
self.class.complete_job(job_transaction)
119
end
1210
end

app/models/concerns/child_minder.rb

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,30 @@ def manage_children
99
newly_deleted = is_deleted_changed? && is_deleted?
1010
yield
1111
if has_children? && newly_deleted
12-
ChildDeletionJob.perform_later(
13-
ChildDeletionJob.initialize_job(self),
14-
self
15-
)
12+
(1..paginated_children.total_pages).each do |page|
13+
ChildDeletionJob.perform_later(
14+
ChildDeletionJob.initialize_job(self),
15+
self,
16+
page
17+
)
18+
end
1619
end
1720
end
1821

19-
def delete_children
20-
children.each do |child|
22+
def has_children?
23+
children.count > 0
24+
end
25+
26+
def delete_children(page)
27+
paginated_children(page).each do |child|
28+
child.current_transaction = current_transaction if child.class.include? ChildMinder
2129
child.update(is_deleted: true)
2230
end
2331
end
2432

25-
def has_children?
26-
children.count > 0
33+
private
34+
35+
def paginated_children(page=1)
36+
children.page(page).per(Rails.application.config.max_children_per_job)
2737
end
2838
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Rails.application.config.max_children_per_job = ENV['MAX_CHILDREN_PER_JOB'] ? ENV['MAX_CHILDREN_PER_JOB'].to_i : 100

spec/jobs/child_deletion_job_spec.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,48 @@
11
require 'rails_helper'
22

33
RSpec.describe ChildDeletionJob, type: :job do
4+
5+
shared_examples 'a ChildDeletionJob' do |
6+
parent_sym,
7+
child_folder_sym,
8+
child_file_sym
9+
|
10+
let(:parent) { send(parent_sym) }
11+
let(:job_transaction) { described_class.initialize_job(parent) }
12+
let(:child_folder) { send(child_folder_sym) }
13+
let(:child_file) { send(child_file_sym) }
14+
let(:prefix) { Rails.application.config.active_job.queue_name_prefix }
15+
let(:prefix_delimiter) { Rails.application.config.active_job.queue_name_delimiter }
16+
include_context 'with job runner', described_class
17+
18+
it { is_expected.to be_an ApplicationJob }
19+
it { expect(prefix).not_to be_nil }
20+
it { expect(prefix_delimiter).not_to be_nil }
21+
it { expect(described_class.queue_name).to eq("#{prefix}#{prefix_delimiter}child_deletion") }
22+
it {
23+
expect {
24+
described_class.perform_now
25+
}.to raise_error(ArgumentError)
26+
expect {
27+
described_class.perform_now(job_transaction)
28+
}.to raise_error(ArgumentError)
29+
expect {
30+
described_class.perform_now(job_transaction, parent)
31+
}.to raise_error(ArgumentError)
32+
}
33+
34+
context 'perform_now' do
35+
let(:page) { 1 }
36+
37+
it {
38+
expect(child_folder).to be_persisted
39+
expect(child_file).to be_persisted
40+
expect(parent).to receive(:delete_children).with(page)
41+
described_class.perform_now(job_transaction, parent, page)
42+
}
43+
end
44+
end
45+
446
before do
547
expect(folder_child).to be_persisted
648
end

spec/support/concerns/child_minder_shared_examples.rb

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@
6565
ChildDeletionJob.initialize_job(subject)
6666
}
6767
before do
68+
@old_max = Rails.application.config.max_children_per_job
69+
Rails.application.config.max_children_per_job = 1
6870
expect(child_folder).to be_persisted
6971
expect(child_folder.is_deleted?).to be_falsey
7072
expect(valid_child_file).to be_persisted
@@ -73,13 +75,19 @@
7375
expect(invalid_child_file.is_deleted?).to be_falsey
7476
end
7577

78+
after do
79+
Rails.application.config.max_children_per_job = @old_max
80+
end
81+
7682
it {
7783
expect(subject).to be_has_children
7884
subject.is_deleted = true
7985
yield_called = false
80-
expect(ChildDeletionJob).to receive(:initialize_job)
81-
.with(subject).and_return(job_transaction)
82-
expect(ChildDeletionJob).to receive(:perform_later).with(job_transaction, subject)
86+
expect(ChildDeletionJob).to receive(:initialize_job).exactly(subject.children.count)
87+
.with(subject).times.and_return(job_transaction)
88+
(1..subject.children.count).each do |page|
89+
expect(ChildDeletionJob).to receive(:perform_later).with(job_transaction, subject, page)
90+
end
8391
subject.manage_children do
8492
yield_called = true
8593
end
@@ -133,23 +141,41 @@
133141
end
134142

135143
describe '#delete_children' do
136-
it {
137-
is_expected.to respond_to(:delete_children)
138-
}
139-
it {
140-
expect(child_folder).to be_persisted
141-
expect(child_folder.is_deleted?).to be_falsey
142-
expect(valid_child_file).to be_persisted
143-
expect(valid_child_file.is_deleted?).to be_falsey
144-
expect(invalid_child_file).to be_persisted
145-
expect(invalid_child_file.is_deleted?).to be_falsey
146-
subject.delete_children
147-
expect(child_folder.reload).to be_truthy
148-
expect(child_folder.is_deleted?).to be_truthy
149-
valid_child_file.reload
150-
expect(valid_child_file.is_deleted?).to be_truthy
151-
invalid_child_file.reload
152-
expect(invalid_child_file.is_deleted?).to be_truthy
153-
}
144+
it { is_expected.not_to respond_to(:delete_children).with(0).arguments }
145+
it { is_expected.to respond_to(:delete_children).with(1).argument }
146+
147+
context 'called', :vcr do
148+
let(:job_transaction) { ChildDeletionJob.initialize_job(subject) }
149+
let(:child_job_transaction) { ChildDeletionJob.initialize_job(child_folder) }
150+
let(:child_folder_file) { FactoryGirl.create(:data_file, parent: child_folder)}
151+
let(:page) { 1 }
152+
153+
before do
154+
expect(child_folder).to be_persisted
155+
expect(child_folder_file).to be_persisted
156+
expect(valid_child_file.is_deleted?).to be_falsey
157+
@old_max = Rails.application.config.max_children_per_job
158+
Rails.application.config.max_children_per_job = subject.children.count + child_folder.children.count
159+
end
160+
161+
after do
162+
Rails.application.config.max_children_per_job = @old_max
163+
end
164+
165+
it {
166+
subject.current_transaction = job_transaction
167+
expect(ChildDeletionJob).to receive(:initialize_job)
168+
.with(child_folder)
169+
.and_return(child_job_transaction)
170+
expect(ChildDeletionJob).to receive(:perform_later)
171+
.with(child_job_transaction, child_folder, page).and_call_original
172+
subject.delete_children(page)
173+
expect(child_folder.reload).to be_truthy
174+
expect(child_folder.is_deleted?).to be_truthy
175+
expect(valid_child_file.reload).to be_truthy
176+
expect(valid_child_file.is_deleted?).to be_truthy
177+
}
178+
end
179+
154180
end
155-
end
181+
end

spec/support/job_shared_examples.rb

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -163,52 +163,3 @@
163163
.and_call_original
164164
end
165165
end
166-
167-
shared_examples 'a ChildDeletionJob' do |
168-
parent_sym,
169-
child_folder_sym,
170-
child_file_sym
171-
|
172-
let(:parent) { send(parent_sym) }
173-
let(:job_transaction) { described_class.initialize_job(parent) }
174-
let(:child_folder) { send(child_folder_sym) }
175-
let(:child_file) { send(child_file_sym) }
176-
let(:prefix) { Rails.application.config.active_job.queue_name_prefix }
177-
let(:prefix_delimiter) { Rails.application.config.active_job.queue_name_delimiter }
178-
include_context 'with job runner', described_class
179-
180-
it { is_expected.to be_an ApplicationJob }
181-
it { expect(prefix).not_to be_nil }
182-
it { expect(prefix_delimiter).not_to be_nil }
183-
it { expect(described_class.queue_name).to eq("#{prefix}#{prefix_delimiter}child_deletion") }
184-
it {
185-
expect {
186-
described_class.perform_now
187-
}.to raise_error(ArgumentError)
188-
expect {
189-
described_class.perform_now(parent)
190-
}.to raise_error(ArgumentError)
191-
}
192-
193-
context 'perform_now', :vcr do
194-
let(:child_job_transaction) { described_class.initialize_job(child_folder) }
195-
include_context 'tracking job', :job_transaction
196-
197-
it {
198-
expect(child_folder).to be_persisted
199-
expect(child_file.is_deleted?).to be_falsey
200-
201-
expect(described_class).to receive(:initialize_job)
202-
.with(child_folder)
203-
.and_return(child_job_transaction)
204-
expect(described_class).to receive(:perform_later)
205-
.with(child_job_transaction, child_folder).and_call_original
206-
207-
described_class.perform_now(job_transaction, parent)
208-
expect(child_folder.reload).to be_truthy
209-
expect(child_folder.is_deleted?).to be_truthy
210-
expect(child_file.reload).to be_truthy
211-
expect(child_file.is_deleted?).to be_truthy
212-
}
213-
end
214-
end

0 commit comments

Comments
 (0)