Commit b72dae3f authored by Sean Arnold's avatar Sean Arnold

Add IssueCheckWorker for pending escalations

- Add to Schedule Check Cron worker
- Add new queue to yml files
parent 1bd8f8e3
......@@ -205,6 +205,8 @@
- 1
- - incident_management_pending_escalations_alert_create
- 1
- - incident_management_pending_escalations_issue_check
- 1
- - integrations_create_external_cross_reference
- 1
- - invalid_gpg_signature_update
......
......@@ -27,6 +27,13 @@ module EE
supports_sla?
end
def escalation_policies_available?
return false unless ::Feature.enabled?(:incident_escalations, project)
return false unless ::Gitlab::IncidentManagement.escalation_policies_available?(project)
supports_escalation?
end
def metric_images_available?
return false unless IssuableMetricImage.available_for?(project)
......@@ -41,6 +48,10 @@ module EE
incident?
end
def supports_escalation?
incident?
end
def supports_iterations?
false
end
......
......@@ -28,6 +28,14 @@ module IncidentManagement
scope :processable, -> { where(process_at: ESCALATION_BUFFER.ago..Time.current) }
delegate :project, to: :target
def escalatable
raise NotImplementedError
end
def type
raise NotImplementedError
end
end
end
end
......@@ -12,6 +12,14 @@ module IncidentManagement
belongs_to :alert, class_name: 'AlertManagement::Alert', foreign_key: 'alert_id', inverse_of: :pending_escalations
validates :rule_id, uniqueness: { scope: [:alert_id] }
def escalatable
alert
end
def type
:alert
end
end
end
end
......@@ -12,6 +12,14 @@ module IncidentManagement
belongs_to :issue, class_name: '::Issue', foreign_key: 'issue_id', inverse_of: :pending_escalations
validates :rule_id, uniqueness: { scope: [:issue_id] }
def escalatable
issue.incident_management_issuable_escalation_status
end
def type
:incident
end
end
end
end
......@@ -9,12 +9,12 @@ module EE
def execute(issue)
super
add_issue_sla(issue)
create_issue_sla(issue)
end
private
def add_issue_sla(issue)
def create_issue_sla(issue)
return unless issue.sla_available?
::IncidentManagement::Incidents::CreateSlaService.new(issue, current_user).execute
......
......@@ -76,6 +76,14 @@ module EE
end
end
def notify_oncall_users_of_incident(users, issue)
track_usage_event(:i_incident_management_oncall_notification_sent, users.map(&:id))
users.each do |user|
mailer.incident_escalation_fired_email(issue.project, user, issue).deliver_later
end
end
def oncall_user_removed(rotation, user, async_notification = true)
oncall_user_removed_recipients(rotation, user).each do |recipient|
email = mailer.user_removed_from_rotation_email(user, rotation, [recipient])
......
......@@ -112,8 +112,8 @@ module EE
issuables_service(noteable, project, author).publish_issue_to_status_page
end
def notify_via_escalation(noteable, project, recipients, escalation_policy)
escalations_service(noteable, project).notify_via_escalation(recipients, escalation_policy: escalation_policy)
def notify_via_escalation(noteable, project, recipients, escalation_policy, type)
escalations_service(noteable, project).notify_via_escalation(recipients, escalation_policy: escalation_policy, type: type)
end
private
......
......@@ -8,8 +8,8 @@ module SystemNotes
@author = User.alert_bot
end
def notify_via_escalation(recipients, escalation_policy:)
body = "notified #{recipients.map(&:to_reference).to_sentence} of this alert via escalation policy **#{escalation_policy.name}**"
def notify_via_escalation(recipients, escalation_policy:, type:)
body = "notified #{recipients.map(&:to_reference).to_sentence} of this #{type} via escalation policy **#{escalation_policy.name}**"
create_note(NoteSummary.new(noteable, project, author, body, action: 'new_alert_added'))
end
......
......@@ -1110,6 +1110,15 @@
:weight: 1
:idempotent: true
:tags: []
- :name: incident_management_pending_escalations_issue_check
:worker_name: IncidentManagement::PendingEscalations::IssueCheckWorker
:feature_category: :incident_management
:has_external_dependencies:
:urgency: :high
:resource_boundary: :cpu
:weight: 1
:idempotent: true
:tags: []
- :name: ldap_group_sync
:worker_name: LdapGroupSyncWorker
:feature_category: :authentication_and_authorization
......
# frozen_string_literal: true
module IncidentManagement
module PendingEscalations
class IssueCheckWorker
include ApplicationWorker
data_consistency :always
worker_resource_boundary :cpu
urgency :high
idempotent!
feature_category :incident_management
def perform(escalation_id)
escalation = IncidentManagement::PendingEscalations::Issue.find_by_id(escalation_id)
return unless escalation
IncidentManagement::PendingEscalations::ProcessService.new(escalation).execute
end
end
end
end
......@@ -15,7 +15,12 @@ module IncidentManagement
def perform
::IncidentManagement::PendingEscalations::Alert.processable.each_batch do |relation|
args = relation.pluck(:id).map { |id| [id] } # rubocop:disable CodeReuse/ActiveRecord
::IncidentManagement::PendingEscalations::AlertCheckWorker.bulk_perform_async(args) # rubocop:disable Scalability/BulkPerformWithContext
::IncidentManagement::PendingEscalations::AlertCheckWorker.bulk_perform_async(args) # rubocop:disable Scalability/BulkPerformWithContext
end
::IncidentManagement::PendingEscalations::Issue.processable.each_batch do |relation|
args = relation.pluck(:id).map { |id| [id] } # rubocop:disable CodeReuse/ActiveRecord
::IncidentManagement::PendingEscalations::IssueCheckWorker.bulk_perform_async(args) # rubocop:disable Scalability/BulkPerformWithContext
end
end
end
......
......@@ -108,4 +108,31 @@ RSpec.describe EE::Issuable do
it { is_expected.to eq(supports_iterations) }
end
end
describe '#escalation_policies_available?' do
where(:issuable_type, :incident_escalations_enabled, :oncall_schedules_enabled, :escalation_policies_enabled, :available) do
[
[:issue, true, true, true, false],
[:incident, false, false, false, false],
[:incident, false, true, true, false],
[:incident, true, false, false, false],
[:incident, true, true, false, false],
[:incident, true, false, true, false],
[:incident, true, true, true, true]
]
end
with_them do
let(:issuable) { build_stubbed(issuable_type) }
before do
stub_feature_flags(incident_escalations: incident_escalations_enabled)
stub_licensed_features(oncall_schedules: oncall_schedules_enabled, escalation_policies: escalation_policies_enabled)
end
subject { issuable.escalation_policies_available? }
it { is_expected.to eq(available) }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe IncidentManagement::PendingEscalations::IssueCheckWorker do
let(:worker) { described_class.new }
let_it_be(:escalation) { create(:incident_management_pending_issue_escalation) }
describe '#perform' do
subject { worker.perform(*args) }
context 'with valid escalation' do
let(:args) { [escalation.id.to_s] }
it 'processes the escalation' do
expect_next_instance_of(IncidentManagement::PendingEscalations::ProcessService, escalation) do |service|
expect(service).to receive(:execute)
end
subject
end
end
context 'without valid escalation' do
let(:args) { [non_existing_record_id] }
it 'does nothing' do
expect(IncidentManagement::PendingEscalations::CreateService).not_to receive(:new)
expect { subject }.not_to raise_error
end
end
end
end
......@@ -5,8 +5,10 @@ require 'spec_helper'
RSpec.describe IncidentManagement::PendingEscalations::ScheduleCheckCronWorker do
let(:worker) { described_class.new }
let_it_be(:escalation_1) { create(:incident_management_pending_alert_escalation, process_at: 5.minutes.ago) }
let_it_be(:escalation_2) { create(:incident_management_pending_alert_escalation, process_at: 2.days.ago) }
let_it_be(:alert_escalation_1) { create(:incident_management_pending_alert_escalation, process_at: 5.minutes.ago) }
let_it_be(:alert_escalation_2) { create(:incident_management_pending_alert_escalation, process_at: 2.days.ago) }
let_it_be(:issue_escalation_1) { create(:incident_management_pending_issue_escalation, process_at: 2.days.ago) }
let_it_be(:issue_escalation_2) { create(:incident_management_pending_issue_escalation, process_at: 2.days.ago) }
let_it_be(:escalation_not_ready_to_process) { create(:incident_management_pending_alert_escalation) }
describe '#perform' do
......@@ -14,7 +16,10 @@ RSpec.describe IncidentManagement::PendingEscalations::ScheduleCheckCronWorker d
it 'schedules a job for each processable escalation' do
expect(IncidentManagement::PendingEscalations::AlertCheckWorker).to receive(:bulk_perform_async)
.with(array_including([escalation_2.id], [escalation_1.id]))
.with(array_including([alert_escalation_2.id], [alert_escalation_1.id]))
expect(IncidentManagement::PendingEscalations::IssueCheckWorker).to receive(:bulk_perform_async)
.with(array_including([issue_escalation_2.id], [issue_escalation_1.id]))
subject
end
......
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