Commit 96369a9d authored by Heinrich Lee Yu's avatar Heinrich Lee Yu

Add a limit to the number of events

We don't know what number to cap this exactly but I think this is a
reasonable first iteration where most regular milestones shouldn't hit
parent 21f561fe
...@@ -8,6 +8,12 @@ ...@@ -8,6 +8,12 @@
# so that we can keep track of the issue's state during that point in time and handle the events based on that. # so that we can keep track of the issue's state during that point in time and handle the events based on that.
class Milestones::BurnupChartService class Milestones::BurnupChartService
include Gitlab::Utils::StrongMemoize
EVENT_COUNT_LIMIT = 50_000
TooManyEventsError = Class.new(StandardError)
def initialize(milestone) def initialize(milestone)
raise ArgumentError, 'Milestone must have a start and due date' if milestone.start_date.blank? || milestone.due_date.blank? raise ArgumentError, 'Milestone must have a start and due date' if milestone.start_date.blank? || milestone.due_date.blank?
...@@ -18,6 +24,8 @@ class Milestones::BurnupChartService ...@@ -18,6 +24,8 @@ class Milestones::BurnupChartService
@issue_states = {} @issue_states = {}
@chart_data = [] @chart_data = []
raise TooManyEventsError if resource_events.num_tuples > EVENT_COUNT_LIMIT
resource_events.each do |event| resource_events.each do |event|
case event['event_type'] case event['event_type']
when 'milestone' when 'milestone'
...@@ -152,9 +160,11 @@ class Milestones::BurnupChartService ...@@ -152,9 +160,11 @@ class Milestones::BurnupChartService
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def resource_events def resource_events
strong_memoize(:resource_events) do
union = Gitlab::SQL::Union.new([milestone_events, state_events, weight_events]) # rubocop: disable Gitlab/Union union = Gitlab::SQL::Union.new([milestone_events, state_events, weight_events]) # rubocop: disable Gitlab/Union
ActiveRecord::Base.connection.execute("(#{union.to_sql}) ORDER BY created_at") ActiveRecord::Base.connection.execute("(#{union.to_sql}) ORDER BY created_at LIMIT #{EVENT_COUNT_LIMIT + 1}")
end
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
......
...@@ -16,6 +16,15 @@ RSpec.describe Milestones::BurnupChartService do ...@@ -16,6 +16,15 @@ RSpec.describe Milestones::BurnupChartService do
expect { described_class.new(milestone) }.to raise_error('Milestone must have a start and due date') expect { described_class.new(milestone) }.to raise_error('Milestone must have a start and due date')
end end
it 'raises an error when the number of events exceeds the limit' do
stub_const('Milestones::BurnupChartService::EVENT_COUNT_LIMIT', 1)
create(:resource_milestone_event, issue: issues[0], milestone: milestone, action: :add, created_at: '2019-12-15')
create(:resource_milestone_event, issue: issues[1], milestone: milestone, action: :add, created_at: '2019-12-16')
expect { chart_data }.to raise_error(described_class::TooManyEventsError)
end
it 'aggregates events before the start date to the start date' do it 'aggregates events before the start date to the start date' do
create(:resource_milestone_event, issue: issues[0], milestone: milestone, action: :add, created_at: '2019-12-15') create(:resource_milestone_event, issue: issues[0], milestone: milestone, action: :add, created_at: '2019-12-15')
create(:resource_weight_event, issue: issues[0], weight: 2, created_at: '2019-12-18') create(:resource_weight_event, issue: issues[0], weight: 2, created_at: '2019-12-18')
......
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