Skip to content

Commit

Permalink
API-24392: Add Feature Flag Monitoring Job for VBADocuments (#12256)
Browse files Browse the repository at this point in the history
* API-24392: Add feature flag monitoring job for VBADocuments

* API-24392: Simplify since only DefaultNotification exists for now

* API-24392: Rename  to
  • Loading branch information
kristen-brown authored Mar 30, 2023
1 parent a8dc46b commit 7d9444d
Show file tree
Hide file tree
Showing 9 changed files with 382 additions and 2 deletions.
5 changes: 5 additions & 0 deletions config/sidekiq_scheduler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ VANotify::InProgressForms:
class: VANotify::InProgressForms
description: "In progress form reminder emails (sent via VaNotify)"

VBADocuments::FlipperStatusAlert:
cron: '0 2,9,16 * * MON-FRI America/New_York'
class: VBADocuments::FlipperStatusAlert
description: "Checks status of Flipper features expected to be enabled and alerts to Slack if any are not enabled"

VBADocuments::ReportMonthlySubmissions:
cron: "4 3 2 1 * * America/New_York"
class: VBADocuments::ReportMonthlySubmissions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ class FlipperStatusAlert
DISABLED_FLAG_EMOJI = ':vertical_traffic_light:'
MISSING_FLAG_EMOJI = ':no_entry_sign:'

# No need to retry since the schedule will run this every hour
sidekiq_options retry: false, unique_for: 30.minutes
sidekiq_options retry: 5, unique_for: 30.minutes

def perform
features_to_check = load_features_from_config
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

module VBADocuments
module Slack
class HashNotification
def initialize(params)
# Params are expected to be in the Sidekiq Job Format (https://github.com/mperham/sidekiq/wiki/Job-Format),
@params = params
end

def message_text
msg = "ENVIRONMENT: #{environment}".dup

params.each do |k, v|
msg << "\n#{k.to_s.upcase} : #{v}"
end

msg
end

private

attr_accessor :params

def environment
env = Settings.vsp_environment

env_emoji = Messenger::ENVIRONMENT_EMOJIS[env.to_sym]

":#{env_emoji}: #{env} :#{env_emoji}:"
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require 'common/client/base'

module VBADocuments
module Slack
class Messenger
ALERT_URL = Settings.vba_documents.slack.default_alert_url
ENVIRONMENT_EMOJIS = { production: 'rotating_light', sandbox: 'rocket', staging: 'construction',
development: 'brain' }.freeze

def initialize(params)
@params = params
end

def notify!
Faraday.post(ALERT_URL, request_body, request_headers)
end

private

attr_reader :params

def notification
VBADocuments::Slack::HashNotification.new(params)
end

def request_body
{ text: notification.message_text }.to_json
end

def request_headers
{ 'Content-type' => 'application/json; charset=utf-8' }
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# frozen_string_literal: true

require 'sidekiq'
require 'flipper/utilities/bulk_feature_checker'

module VBADocuments
class FlipperStatusAlert
include Sidekiq::Worker

WARNING_EMOJI = ':warning:'
DISABLED_FLAG_EMOJI = ':vertical_traffic_light:'
MISSING_FLAG_EMOJI = ':no_entry_sign:'

sidekiq_options retry: 5, unique_for: 30.minutes

def perform
features_to_check = load_features_from_config
if features_to_check.present?
@feature_statuses = Flipper::Utilities::BulkFeatureChecker.enabled_status(features_to_check)

slack_notify unless all_features_enabled?
end
end

private

def load_features_from_config
file_path = VBADocuments::Engine.root.join('config', 'flipper', 'enabled_features.yml')
feature_hash = read_config_file(file_path)
return [] if feature_hash.nil?

env_hash = feature_hash.fetch(Settings.vsp_environment.to_s, []) || []
features = (env_hash + (feature_hash['common'] || [])).uniq.sort

if features.empty?
VBADocuments::Slack::Messenger.new(
{
warning: "#{WARNING_EMOJI} #{self.class.name} has no configured enabled features",
file_path: file_path.to_s
}
).notify!
end

features
end

def read_config_file(path)
if File.exist?(path)
YAML.load_file(path) || {}
else
VBADocuments::Slack::Messenger.new(
{
warning: "#{WARNING_EMOJI} #{self.class.name} features file does not exist",
file_path: path.to_s
}
).notify!
nil
end
end

def all_features_enabled?
@feature_statuses[:missing].empty? && @feature_statuses[:disabled].empty?
end

def slack_notify
slack_details = {
class: self.class.name,
warning: "#{WARNING_EMOJI} One or more features expected to be enabled were found disabled or missing",
disabled_flags: slack_message(:disabled),
missing_flags: slack_message(:missing)
}

VBADocuments::Slack::Messenger.new(slack_details).notify!
end

def slack_message(flag_category)
if @feature_statuses[flag_category].present?
emoji = self.class.const_get("#{flag_category.upcase}_FLAG_EMOJI")
"#{emoji} #{@feature_statuses[flag_category].join(', ')} #{emoji}"
else
'None'
end
end
end
end
6 changes: 6 additions & 0 deletions modules/vba_documents/config/flipper/enabled_features.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
common:
- test_feature_flag_alert_temp
development:
staging:
sandbox:
production:
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

require 'rails_helper'

describe VBADocuments::Slack::HashNotification do
describe '#message_text' do
let(:params) do
{
'test_key' => 'test_value',
'args' => %w[1234 5678],
'gibberish' => 2,
'indeed' => 'indeed gibberish',
'message' => 'Something happened here'
}
end

it 'returns the VSP environment' do
with_settings(Settings, vsp_environment: 'staging') do
expect(
described_class.new(params).message_text
).to include('ENVIRONMENT: :construction: staging :construction:')
end
end

it 'displays all the keys capitalized and formatted' do
with_settings(Settings, vsp_environment: 'staging') do
expect(described_class.new(params).message_text).to include(
"\nTEST_KEY : test_value\nARGS : [\"1234\", \"5678\"]
GIBBERISH : 2\nINDEED : indeed gibberish\nMESSAGE : Something happened here"
)
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

require 'rails_helper'

describe VBADocuments::Slack::Messenger do
describe '.notify!' do
let(:params) do
{
'class' => 'SomeClass',
'args' => %w[1234 5678],
'retry_count' => 2,
'error_class' => 'RuntimeError',
'error_message' => 'Here there be dragons',
'failed_at' => 1_613_670_737.966083,
'retried_at' => 1_613_680_062.5507782
}
end

it 'sends a network request' do
with_settings(Settings, vsp_environment: 'production') do
with_settings(Settings.vba_documents.slack, default_alert_url: 'default alert url') do
body = { text: VBADocuments::Slack::HashNotification.new(params).message_text }.to_json
headers = { 'Content-type' => 'application/json; charset=utf-8' }

allow(Faraday).to receive(:post).with(VBADocuments::Slack::Messenger::ALERT_URL, body, headers)

VBADocuments::Slack::Messenger.new(params).notify!

expect(Faraday).to have_received(:post).with(VBADocuments::Slack::Messenger::ALERT_URL, body, headers)
end
end
end
end
end
Loading

0 comments on commit 7d9444d

Please sign in to comment.