Skip to content

Commit

Permalink
Merge branch 'feat/DEX-2311/add-render-lambda' into 'master'
Browse files Browse the repository at this point in the history
[DEX-2311] feat: Add `action.render` lambda

Closes DEX-2311

See merge request nstmrt/rubygems/sbmt-strangler!19
  • Loading branch information
chernenkov-ayu-sbmt committed Jun 5, 2024
2 parents aaf43d8 + ad84f10 commit ecfd95f
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 17 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [0.8.0] - 2024-06-05

### Added
- Add `action.render = ->(mirror_result) { ... }` lambda

## [0.7.0] - 2024-06-03

### Added
Expand Down
3 changes: 3 additions & 0 deletions config/initializers/yabeda.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ module Yabeda
counter :compare_call_result,
comment: "Compare lambda call result counter (value: true, false)",
tags: %i[value params controller action]
counter :render_call,
comment: "Render lambda call counter (success: true, false)",
tags: %i[success params controller action]
end
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/sbmt/strangler/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Action
option :proxy_http_method, default: :get
option :mirror, default: ->(_rails_controller) {}
option :compare, default: ->(_origin_result, _mirror_result) { false }
option :render, default: ->(mirror_result) { mirror_result }

attr_reader :name, :controller

Expand Down
5 changes: 5 additions & 0 deletions lib/sbmt/strangler/metric_tracker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ def track_compare_call_result(value)
::Yabeda.sbmt_strangler.compare_call_result.increment(yabeda_tags)
end

def track_render_call(success)
yabeda_tags = common_tags.merge(success: success.to_s)
::Yabeda.sbmt_strangler.render_call.increment(yabeda_tags)
end

private

delegate :http_params, :allowed_params, :controller_path, :action_name, to: :rails_controller
Expand Down
2 changes: 1 addition & 1 deletion lib/sbmt/strangler/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module Sbmt
module Strangler
VERSION = "0.7.0"
VERSION = "0.8.0"
end
end
51 changes: 47 additions & 4 deletions lib/sbmt/strangler/work_modes/replace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,59 @@ module Sbmt
module Strangler
module WorkModes
class Replace < Base
include Dry::Monads::Result::Mixin

def call
mirror_result = strangler_action.mirror.call(rails_controller)
track_mirror_call(true)
render mirror_result
mirror_call_result = mirror_call
track_mirror_call(mirror_call_result.success?)

unless mirror_call_result.success?
render(
json: {error: "Mirror lambda call failed!"},
status: :internal_server_error
) # TODO: Возможно стоит сделать фолбэк на проксирование?
return
end

render_call_result = render_call(mirror_call_result.value!)
track_render_call(render_call_result.success?)

unless render_call_result.success?
render(
json: {error: "Render lambda call failed!"},
status: :internal_server_error
) # TODO: Возможно стоит сделать фолбэк на проксирование?
return
end

render render_call_result.value!
end

private

delegate :render, to: :rails_controller
delegate :track_mirror_call, to: :metric_tracker
delegate :track_mirror_call, :track_render_call, to: :metric_tracker

def mirror_call
value = strangler_action.mirror.call(rails_controller)
Success(value)
rescue => err
handle_error(err)
Failure(nil)
end

def render_call(mirror_result)
value = strangler_action.render.call(mirror_result)
Success(value)
rescue => err
handle_error(err)
Failure(nil)
end

def handle_error(err)
Sbmt::Strangler.error_tracker.error(err)
Sbmt::Strangler.logger.error(err)
end
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions spec/controllers/api/stores_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
let(:params_usage_metric) { Yabeda.sbmt_strangler.params_usage }
let(:work_mode_metric) { Yabeda.sbmt_strangler.work_mode }
let(:mirror_call_metric) { Yabeda.sbmt_strangler.mirror_call }
let(:render_call_metric) { Yabeda.sbmt_strangler.render_call }
let(:params) { {a: 123, lat: 68.4897} }

after do
Expand All @@ -156,6 +157,7 @@
expect(params_usage_metric).to receive(:increment).with(common_tags)
expect(work_mode_metric).to receive(:increment).with(common_tags.merge(mode: "replace"))
expect(mirror_call_metric).to receive(:increment).with(common_tags.merge(success: "true"))
expect(render_call_metric).to receive(:increment).with(common_tags.merge(success: "true"))
end
end
end
Expand Down
7 changes: 5 additions & 2 deletions spec/internal/config/initializers/strangler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@
action.proxy_url = "http://example.com:8080/api/stores"
action.proxy_http_method = :post
action.mirror = ->(_rails_controller) do
{json: '["mirror_result"]', status: :ok}
["mirror_result"]
end
action.compare = ->(origin_result, mirror_result) do
mirror_result[:json] == '["mirror_result"]' &&
mirror_result == ["mirror_result"] &&
origin_result[:body] == '["origin_result"]'
end
action.render = ->(mirror_result) do
{json: mirror_result.to_json, status: :ok}
end
end

controller.action("show") do |action|
Expand Down
8 changes: 4 additions & 4 deletions spec/lib/sbmt/strangler/feature_flags_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
context "with many values" do
let(:ctrl_request_headers) do
ActionDispatch::Http::Headers.from_hash(
"#{described_class::FEATURES_HEADER_NAME}" => "any_other_header, invalid_#{expected_feature_name}"
described_class::FEATURES_HEADER_NAME.to_s => "any_other_header, invalid_#{expected_feature_name}"
)
end

Expand All @@ -146,7 +146,7 @@
context "with one value" do
let(:ctrl_request_headers) do
ActionDispatch::Http::Headers.from_hash(
"#{described_class::FEATURES_HEADER_NAME}" => "invalid_#{expected_feature_name}"
described_class::FEATURES_HEADER_NAME.to_s => "invalid_#{expected_feature_name}"
)
end

Expand All @@ -158,7 +158,7 @@
context "with many values" do
let(:ctrl_request_headers) do
ActionDispatch::Http::Headers.from_hash(
"#{described_class::FEATURES_HEADER_NAME}" => "any_other_header, #{expected_feature_name}"
described_class::FEATURES_HEADER_NAME.to_s => "any_other_header, #{expected_feature_name}"
)
end

Expand All @@ -168,7 +168,7 @@
context "with string value" do
let(:ctrl_request_headers) do
ActionDispatch::Http::Headers.from_hash(
"#{described_class::FEATURES_HEADER_NAME}" => "#{expected_feature_name}"
described_class::FEATURES_HEADER_NAME.to_s => expected_feature_name.to_s
)
end

Expand Down
6 changes: 6 additions & 0 deletions spec/lib/sbmt/strangler/metric_tracker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@
include_examples "increments Yabeda metric", :compare_call_result, {value: "false"}
end

describe "#track_render_call" do
subject(:call) { tracker.track_render_call(true) }

include_examples "increments Yabeda metric", :render_call, {success: "true"}
end

describe "#log_unallowed_params" do
it "logs unallowed params" do
expect(Sbmt::Strangler.logger).to receive(:log_warn).with(<<~WARN.strip).and_call_original
Expand Down
91 changes: 86 additions & 5 deletions spec/lib/sbmt/strangler/work_modes/replace_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,100 @@
include_context "with work mode implementation context"

before do
allow(metric_tracker).to receive(:track_mirror_call)
# Rendering
allow(rails_controller).to receive(:render)

# Metrics
allow(metric_tracker).to receive(:track_mirror_call)
allow(metric_tracker).to receive(:track_render_call)

# Lambdas
allow(strangler_action.mirror).to receive(:call).and_call_original
allow(strangler_action.render).to receive(:call).and_call_original
end

it "renders result of mirror block call" do
expect(strangler_action.mirror).to receive(:call).with(rails_controller).and_call_original
it "calls action.mirror lambda" do
mode.call
expect(rails_controller).to have_received(:render).with(mirror_result)
expect(strangler_action.mirror).to have_received(:call).with(rails_controller)
end

it "tracks mirror block call" do
it "tracks action.mirror block call" do
mode.call
expect(metric_tracker).to have_received(:track_mirror_call).with(true)
end

it "calls action.render lambda" do
mode.call
expect(strangler_action.render).to have_received(:call).with(mirror_result)
end

it "tracks action.render block call" do
mode.call
expect(metric_tracker).to have_received(:track_render_call).with(true)
end

it "renders the result of render block call" do
mode.call
expect(rails_controller).to have_received(:render).with(render_result)
end

context "when action.mirror block call raised error" do
let(:error) { RuntimeError.new("something went wrong") }

before do
allow(strangler_action.mirror).to receive(:call).and_raise(error)
end

it "renders error" do
mode.call
expect(rails_controller).to have_received(:render).with(
json: {error: "Mirror lambda call failed!"},
status: :internal_server_error
)
end

it "tracks action.mirror block failure" do
mode.call
expect(metric_tracker).to have_received(:track_mirror_call).with(false)
end

it "doesn't call action.render lambda" do
mode.call
expect(strangler_action.render).not_to have_received(:call)
end

it "tracks/logs error" do
expect(Sbmt::Strangler.error_tracker).to receive(:error).with(error)
expect(Sbmt::Strangler.logger).to receive(:error).with(error)
mode.call
end
end

context "when action.render block call raised error" do
let(:error) { RuntimeError.new("something went wrong") }

before do
allow(strangler_action.render).to receive(:call).and_raise(error)
end

it "renders error" do
mode.call
expect(rails_controller).to have_received(:render).with(
json: {error: "Render lambda call failed!"},
status: :internal_server_error
)
end

it "tracks action.render block failure" do
mode.call
expect(metric_tracker).to have_received(:track_render_call).with(false)
end

it "tracks/logs error" do
expect(Sbmt::Strangler.error_tracker).to receive(:error).with(error)
expect(Sbmt::Strangler.logger).to receive(:error).with(error)
mode.call
end
end
end
end
4 changes: 3 additions & 1 deletion spec/lib/sbmt/strangler/work_modes/shared_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
ctrl.action "index" do |act|
act.mirror = ->(_rails_controller) { mirror_result }
act.compare = ->(_origin_result, _mirror_result) { compare_result }
act.render = ->(_mirror_result) { render_result }
end
end
end
Expand All @@ -31,6 +32,7 @@
let(:rails_controller) { instance_double(TestController, controller_path: "test", action_name: "index") }
let(:feature_flags) { instance_double(Sbmt::Strangler::FeatureFlags) }

let(:mirror_result) { {json: ["mirror_result"], status: :ok} }
let(:mirror_result) { ["mirror_result"] }
let(:compare_result) { true }
let(:render_result) { {json: '["mirror_result"]', status: :ok} }
end

0 comments on commit ecfd95f

Please sign in to comment.