Skip to content

Instantly share code, notes, and snippets.

@CGA1123
Last active January 14, 2020 12:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CGA1123/93a8a46b1f61c0470a57446341f5e52b to your computer and use it in GitHub Desktop.
Save CGA1123/93a8a46b1f61c0470a57446341f5e52b to your computer and use it in GitHub Desktop.
umbra setup example
# config/initializers/umbra.rb
require 'umbra'
Umbra.configure do |config|
config.redis_options = { url: ENV['REDISCLOUD_URL'] } # connect to our redis instance
config.error_handler = proc { |e| Bugsnag.notify(e) } # notify our error tracker
config.request_selector = proc { |env, _resp| env['REQUEST_METHOD'] == 'GET' } # only replicate GET requests
config.logger = Rails.logger
end
Rails.application.config.middleware.use Umbra::Middleware
# lib/shadower/sampler.rb
# frozen_string_literal: true
# A class intended to be passed to `Umbra::ShadoweRequester` as it's `count:`
# argument in order to enable more dynamic load-testing
# powered by LaunchDarkly.
class Shadower
class Sampler
DEFAULT_CONFIG = { enabled: false, multiplier: '0' }.freeze
class << self
def times(&block)
sample = sample(flag)
Umbra.logger.info "[umbra] sampled: #{sample}"
sample.times(&block)
end
private
def sample(config)
return 0 unless config.fetch(:enabled)
multiplier = config.fetch(:multiplier).to_f
integer_part = multiplier.floor
decimal_part = multiplier - integer_part
rand < decimal_part ? integer_part + 1 : integer_part
end
def flag
CarwowFlags.variation(
'umbra',
{ key: 'internal', custom: { groups: [L10n.country] } },
DEFAULT_CONFIG
).symbolize_keys
end
end
end
end
# lib/shadower.rb
# frozen_string_literal: true
# a custom wrapper around the default Umbra::ShadowRequester to enable
# dynamic configuration of endpoints to shadow and the 'multiplier' by
# which to repeat requests by
class Shadower
def self.default
start(count: Shadower::Sampler, pool: 100)
end
def self.start(count: 1, pool: 10, max_queue_size: 100)
Umbra::Subscriber.new(
new(count: count, pool: pool, max_queue_size: max_queue_size)
).start
end
def initialize(count: 1, pool: 10, max_queue_size: 100)
@count = count
@pool = pool
@max_queue_size = max_queue_size
end
def call(payload)
method = payload.dig('request', 'method')
return unless method == 'GET'
return unless path_match?(payload.dig('request', 'path_info'))
Umbra.logger.info "[umbra] Path match: #{payload.dig('request', 'path_info')}"
shadow_requester.call(payload)
end
def shadow_requester
@shadow_requester ||= Umbra::ShadowRequester.new(count: @count, pool: @pool, max_queue_size: @max_queue_size)
end
def path_match?(path)
# CarwowFlags is an internal wrapper around LaunchDarkly's client
CarwowFlags.variation(
'umbra-whitelist',
{ key: 'internal', custom: { groups: [L10n.country] } },
[]
).any? { |regex_str| Regexp.new(regex_str).match?(path) }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment