Skip to content

Commit

Permalink
[DEX-2143] feat: tooling for proxy mode
Browse files Browse the repository at this point in the history
  • Loading branch information
shatalov-boris committed Apr 5, 2024
1 parent 77c0c12 commit 16b2503
Show file tree
Hide file tree
Showing 45 changed files with 1,369 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ tests:
image: dreg.sbmt.io/dhub/library/ruby:$RUBY_VERSION
parallel:
matrix:
- RUBY_VERSION: ['3.0', '3.1', '3.2', '3.3']
- RUBY_VERSION: ['3.1', '3.2', '3.3']
before_script:
- gem install bundler -v 2.5.7
- bin/setup
Expand Down
53 changes: 45 additions & 8 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,54 @@
inherit_gem:
sbmt-dev: config/rubocop.yml
inherit_from: .rubocop_todo.yml

# We want Exclude directives from different
# config files to get merged, not overwritten
inherit_mode:
merge:
- Exclude

AllCops:
TargetRubyVersion: 3.3
TargetRailsVersion: 7.1
Exclude:
- spec/support/grpc/**/*
NewCops: enable
SuggestExtensions: false

require:
# Performance cops are bundled with Standard
- rubocop-performance
- rubocop-rails
- rubocop-rspec
# Standard's config uses custom cops,
# so it must be loaded
- standard

inherit_gem:
standard: config/base.yml

# rubocop-rails
Rails/SkipsModelValidations:
Enabled: false

Style/StringLiterals:
EnforcedStyle: single_quotes
# rubocop-rspec
RSpec/AnyInstance:
Enabled: false

RSpec/FilePath:
RSpec/MultipleExpectations:
Enabled: false

RSpec/SpecFilePathFormat:
RSpec/LetSetup:
Enabled: false

RSpec/StubbedMock:
Enabled: false

RSpec/MessageSpies:
Enabled: false

RSpec/NestedGroups:
Max: 10

RSpec/ExampleLength:
Max: 35

RSpec/MultipleMemoizedHelpers:
Max: 15
Empty file added .rubocop_todo.yml
Empty file.
9 changes: 4 additions & 5 deletions Appraisals
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@
# See compatibility table at https://www.fastruby.io/blog/ruby/rails/versions/compatibility-table.html

versions_map = {
'6.1' => %w[3.0],
'7.0' => %w[3.1],
'7.1' => %w[3.2 3.3]
"7.0" => %w[3.1],
"7.1" => %w[3.2 3.3]
}

current_ruby_version = RUBY_VERSION.split('.').first(2).join('.')
current_ruby_version = RUBY_VERSION.split(".").first(2).join(".")

versions_map.each do |rails_version, ruby_versions|
ruby_versions.each do |ruby_version|
next if ruby_version != current_ruby_version

appraise "railties-#{ruby_version}-#{rails_version}" do
gem 'railties', "~> #{rails_version}.0"
gem "railties", "~> #{rails_version}.0"
end
end
end
7 changes: 1 addition & 6 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
# frozen_string_literal: true

source 'https://nexus.sbmt.io/repository/rubygems/'
source "https://nexus.sbmt.io/repository/rubygems/"

gemspec

source 'https://nexus.sbmt.io/repository/ruby-gems-sbermarket/' do
gem 'sbmt-app', '~> 1.34'
gem 'sbmt-dev', '~> 0.14'
end
6 changes: 3 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# frozen_string_literal: true

require 'bundler/gem_tasks'
require 'rspec/core/rake_task'
require "bundler/gem_tasks"
require "rspec/core/rake_task"

RSpec::Core::RakeTask.new(:spec)

require 'rubocop/rake_task'
require "rubocop/rake_task"

RuboCop::RakeTask.new

Expand Down
5 changes: 5 additions & 0 deletions config/initializers/strangler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

Rails.application.config.after_initialize do
Sbmt::Strangler::Builder.call!
end
20 changes: 20 additions & 0 deletions config/initializers/yabeda.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

module Sbmt
module Strangler
module Metrics
module Yabeda
::Yabeda.configure do
group :sbmt_strangler do
counter :params_usage,
comment: "Parameters usage counter",
tags: %i[params controller action]
counter :work_mode,
comment: "Strangler mode counter: proxy, parallel, render",
tags: %i[mode params controller action]
end
end
end
end
end
end
64 changes: 64 additions & 0 deletions lib/sbmt/strangler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

require "rails"
require "dry-monads"
require "yabeda"
require "faraday"
require "faraday/net_http_persistent"
require "oj"

begin
require "sentry-rails"
rescue LoadError
# optional dependency
end

require_relative "strangler/configurable"
require_relative "strangler/action"
require_relative "strangler/controller"
require_relative "strangler/configuration"
require_relative "strangler/mixin"
require_relative "strangler/builder"
require_relative "strangler/action_invoker"
require_relative "strangler/const_definer"
require_relative "strangler/error_tracker"
require_relative "strangler/logger"
require_relative "strangler/http"

require_relative "strangler/engine"

module Sbmt
module Strangler
module_function

# Public: Configure strangler.
#
# Sbmt::Strangler.configure do |config|
# config.controller(...) do |controller|
# controller.action(...) do {...}
# end
# end
#
# Yields Sbmt::Strangler::Configuration instance.
def configure
yield configuration if block_given?
end

# Public: Returns Sbmt::Strangler::Configuration instance.
def configuration
@configuration ||= Configuration.new
end

def action_controller_base_class
@action_controller_base_class ||= configuration.action_controller_base_class.constantize
end

def error_tracker
@error_tracker ||= configuration.error_tracker.constantize
end

def logger
@logger ||= configuration.logger.constantize
end
end
end
21 changes: 21 additions & 0 deletions lib/sbmt/strangler/action.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module Sbmt
module Strangler
class Action
extend Sbmt::Strangler::Configurable

option :params_tracking_allowlist, :headers_allowlist, default_from: :@controller

attr_accessor :proxy_url, :proxy_http_verb
attr_reader :name

def initialize(name, controller, &)
@name = name
@controller = controller

yield(self)
end
end
end
end
27 changes: 27 additions & 0 deletions lib/sbmt/strangler/action_invoker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

module Sbmt
module Strangler
class ActionInvoker
WORK_MODE = {
proxy: "proxy"
}.freeze

def initialize(action, rails_controller)
@action = action
@rails_controller = rails_controller
end

delegate :http_params, :http_request, :render_proxy_response, :track_params_usage,
:track_work_tactic, to: :@rails_controller

def call
track_params_usage
track_work_tactic(WORK_MODE[:proxy])

response = http_request(http_params)
render_proxy_response(response)
end
end
end
end
29 changes: 29 additions & 0 deletions lib/sbmt/strangler/builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module Sbmt
module Strangler
class Builder
class << self
def call!(configuration = Sbmt::Strangler.configuration)
configuration.controllers.each do |controller|
unless Object.const_defined?(controller.name)
Sbmt::Strangler::ConstDefiner.call!(controller.name, Class.new(Sbmt::Strangler.action_controller_base_class))
end

controller.name.constantize.class_eval do
include Sbmt::Strangler::Mixin

controller.actions.each do |action|
define_method(action.name) do
@strangler_action = action

Sbmt::Strangler::ActionInvoker.new(action, self).call
end
end
end
end
end
end
end
end
end
28 changes: 28 additions & 0 deletions lib/sbmt/strangler/configurable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

module Sbmt
module Strangler
module Configurable
def option(*hash)
hash in [*attributes, Hash => options]

attributes.each do |attribute|
define_method :"#{attribute}=" do |value|
instance_variable_set(:"@#{attribute}", value)
end

define_method attribute.to_s do
value = instance_variable_get(:"@#{attribute}")
return value if value

if options[:default_from]
value = instance_variable_get(options[:default_from])&.public_send(attribute)
end

value || options[:default]
end
end
end
end
end
end
33 changes: 33 additions & 0 deletions lib/sbmt/strangler/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module Sbmt
module Strangler
class Configuration
extend Sbmt::Strangler::Configurable

option :params_tracking_allowlist, :headers_allowlist, default: []
option :action_controller_base_class, default: "ActionController::Base"
option :error_tracker, default: "Sbmt::Strangler::ErrorTracker"
option :logger, default: "Sbmt::Strangler::Logger"

attr_reader :controllers, :http

def initialize(options = {})
@controllers = []
@http = ActiveSupport::OrderedOptions.new.tap do |c|
c.client = "Sbmt::Strangler::Http::Client"
c.keepalive_pool_size = Sbmt::Strangler::Http::DEFAULT_KEEPALIVE_POOL_SIZE
c.keepalive_idle_timeout = Sbmt::Strangler::Http::DEFAULT_KEEPALIVE_IDLE_TIMEOUT
c.timeout = Sbmt::Strangler::Http::DEFAULT_TIMEOUT
c.read_timeout = Sbmt::Strangler::Http::DEFAULT_READ_TIMEOUT
c.write_timeout = Sbmt::Strangler::Http::DEFAULT_WRITE_TIMEOUT
c.open_timeout = Sbmt::Strangler::Http::DEFAULT_OPEN_TIMEOUT
end
end

def controller(name, &)
@controllers.push(Sbmt::Strangler::Controller.new(name, self, &))
end
end
end
end
36 changes: 36 additions & 0 deletions lib/sbmt/strangler/const_definer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

module Sbmt
module Strangler
class ConstDefiner
class << self
def call!(name, klass)
const_names = name.split("::")
class_name = const_names.pop
module_name = if const_names.any?
define_modules(const_names)
else
Object
end

module_name.const_set(class_name, klass)
end

private

def define_modules(module_names)
module_names.reduce(Object) do |parent_module_name, module_name|
define_module(module_name, parent_module_name)
"#{parent_module_name}::#{module_name}".constantize
end
end

def define_module(module_name, parent_module_name)
return if parent_module_name.const_defined?(module_name)

parent_module_name.const_set(module_name, Module.new)
end
end
end
end
end
Loading

0 comments on commit 16b2503

Please sign in to comment.