dhc 2.0.1 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14a53cb09332bb3da43ed44f070d8671b34d5881f4a4b6b44ae4403d90a95ad9
4
- data.tar.gz: 1d1b3a129ad75f53cbe0c1bc03add6805c678f88eb2fc40038c21183742ef69e
3
+ metadata.gz: 0f70dd2da0d8ec740cf21499fc95ba815a73730c2e1c6a4b8cfef6ff18eef0ce
4
+ data.tar.gz: b0773620c07f30f040439d1c56c7a144ee2f144eb0d987d885aec2b940367b6a
5
5
  SHA512:
6
- metadata.gz: c6beddb11566cab553e511ccc16e626ec9139a14d18ffb3ae60ea3312867e4a207c8f68c2da77494c6b72a487ea845194d4d9ef87fee11ff4aad87850397e955
7
- data.tar.gz: c82721bc5c65649dc0084a739c9ec69dfab35ebb932c06ad62cfc86280dd2e38e0bd8651c74705a06ff1c7e1c9fe64aed17c41ccf747df5a178c8dbe61387915
6
+ metadata.gz: 3c652d89a8d1dcbeadf72472322881ce136692d1b51630c61f4cf0b058ff96d9ded1345c80238fa5d46599d494328ebaecc007a915283eae1971efe89de8cea6
7
+ data.tar.gz: 9f71766d909205e3771cd2cfd65130458ac6a73bf35119bd6edf83f1de1ecba418611b66544affd4572b4b275641875d6ae6507fd4a4d07ad1609ae263ff1694
data/.rubocop.yml CHANGED
@@ -62,6 +62,9 @@ Style/SingleArgumentDig:
62
62
  Metrics/ClassLength:
63
63
  Enabled: false
64
64
 
65
+ Metrics/PerceivedComplexity:
66
+ Enabled: false
67
+
65
68
  Style/OptionalBooleanParameter:
66
69
  Enabled: false
67
70
 
data/README.md CHANGED
@@ -854,6 +854,8 @@ If it raises, it forwards the request and response object to rollbar, which cont
854
854
 
855
855
  The throttle interceptor allows you to raise an exception if a predefined quota of a provider request limit is reached in advance.
856
856
 
857
+ The throttle state (tracker) is stored in Rails.cache.
858
+
857
859
  ```ruby
858
860
  DHC.configure do |c|
859
861
  c.interceptors = [DHC::Throttle]
@@ -889,10 +891,33 @@ DHC.get('http://depay.fi', options)
889
891
  * `remaining`:
890
892
  * a hash pointing at the response header containing the current amount of remaining requests
891
893
  * a proc that receives the response as argument and returns the current amount of remaining requests
894
+ * not set: will track remaining by counting down limit until `expires`
892
895
  * `expires`:
893
896
  * a hash pointing at the response header containing the timestamp when the quota will reset
894
897
  * a proc that receives the response as argument and returns the timestamp when the quota will reset
898
+ * an ActiveSupport::Duration e.g. 1.minute
899
+
900
+ Example for throttling manually without relating to any information in the response:
895
901
 
902
+ ```ruby
903
+ options = {
904
+ throttle: {
905
+ track: true,
906
+ break: '80%',
907
+ provider: 'depay.fi',
908
+ limit: 100,
909
+ expires: 1.minute
910
+ }
911
+ }
912
+
913
+ DHC.get('http://depay.fi', options)
914
+ ```
915
+
916
+ Will reset every minute, and will allow up to 80 requests per minute. The 81st request attempt within a minute will raise:
917
+
918
+ ```ruby
919
+ DHC::Throttle::OutOfQuota: Reached predefined quota for depay.fi
920
+ ```
896
921
 
897
922
  #### Zipkin
898
923
 
data/dhc.gemspec CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
28
28
 
29
29
  s.add_development_dependency 'prometheus-client', '~> 0.7.1'
30
30
  s.add_development_dependency 'pry'
31
- s.add_development_dependency 'rails', '>= 5.2'
31
+ s.add_development_dependency 'rails', '>= 5.2', '< 7'
32
32
  s.add_development_dependency 'redis'
33
33
  s.add_development_dependency 'rspec-rails', '>= 3.0.0'
34
34
  s.add_development_dependency 'rubocop'
@@ -23,12 +23,12 @@ class DHC::Caching < DHC::Interceptor
23
23
  def fetch(key)
24
24
  central_response = @central[:read].fetch(key) if @central && @central[:read].present?
25
25
  if central_response
26
- puts %([DHC] served from central cache: "#{key}")
26
+ DHC::Logger.info %([DHC] served from central cache: "#{key}")
27
27
  return central_response
28
28
  end
29
29
  local_response = @local.fetch(key) if @local
30
30
  if local_response
31
- puts %([DHC] served from local cache: "#{key}")
31
+ DHC::Logger.info %([DHC] served from local cache: "#{key}")
32
32
  return local_response
33
33
  end
34
34
  end
@@ -6,80 +6,117 @@ class DHC::Throttle < DHC::Interceptor
6
6
  class OutOfQuota < StandardError
7
7
  end
8
8
 
9
+ CACHE_KEY = 'DHC/throttle/tracker/v1'
10
+
9
11
  class << self
10
- attr_accessor :track
12
+
13
+ def tracker(provider)
14
+ (Rails.cache.read(CACHE_KEY) || {})[provider] || {}
15
+ end
16
+
17
+ def tracker=(track)
18
+ Rails.cache.write(CACHE_KEY, (Rails.cache.read(CACHE_KEY) || {}).merge({ track[:provider] => track }))
19
+ end
11
20
  end
12
21
 
13
22
  def before_request
14
- options = request.options.dig(:throttle)
15
23
  return unless options
16
- break_options = options.dig(:break)
17
- return unless break_options
18
- break_when_quota_reached! if break_options.match('%')
24
+ break! if break?
19
25
  end
20
26
 
21
27
  def after_response
22
- options = response.request.options.dig(:throttle)
23
- return unless throttle?(options)
24
- self.class.track ||= {}
25
- self.class.track[options.dig(:provider)] = {
26
- limit: limit(options: options[:limit], response: response),
27
- remaining: remaining(options: options[:remaining], response: response),
28
- expires: expires(options: options[:expires], response: response)
28
+ return unless track?
29
+ self.class.tracker = {
30
+ provider: options.dig(:provider),
31
+ limit: limit,
32
+ remaining: remaining,
33
+ expires: expires
29
34
  }
30
35
  end
31
36
 
32
37
  private
33
38
 
34
- def throttle?(options)
35
- [options&.dig(:track), response.headers].none?(&:blank?)
39
+ def options
40
+ @options ||= request.options.dig(:throttle) || {}
41
+ end
42
+
43
+ def provider
44
+ @provider ||= request.options.dig(:throttle, :provider)
45
+ end
46
+
47
+ def track?
48
+ (options.dig(:remaining) && [options.dig(:track), response.headers].none?(&:blank?) ||
49
+ options.dig(:track).present?
50
+ )
51
+ end
52
+
53
+ def break?
54
+ @do_break ||= begin
55
+ return if options.dig(:break) && !options.dig(:break).match('%')
56
+ tracker = self.class.tracker(options[:provider])
57
+ return if tracker.blank? || tracker[:remaining].blank? || tracker[:limit].blank? || tracker[:expires].blank?
58
+ return if Time.zone.now > tracker[:expires]
59
+ remaining = tracker[:remaining] * 100
60
+ limit = tracker[:limit]
61
+ remaining_quota = 100 - options[:break].to_i
62
+ remaining <= remaining_quota * limit
63
+ end
36
64
  end
37
65
 
38
- def break_when_quota_reached!
39
- options = request.options.dig(:throttle)
40
- track = (self.class.track || {}).dig(options[:provider])
41
- return if track.blank? || track[:remaining].blank? || track[:limit].blank? || track[:expires].blank?
42
- return if Time.zone.now > track[:expires]
43
- # avoid floats by multiplying with 100
44
- remaining = track[:remaining] * 100
45
- limit = track[:limit]
46
- quota = 100 - options[:break].to_i
47
- raise(OutOfQuota, "Reached predefined quota for #{options[:provider]}") if remaining < quota * limit
66
+ def break!
67
+ raise(OutOfQuota, "Reached predefined quota for #{provider}")
48
68
  end
49
69
 
50
- def limit(options:, response:)
70
+ def limit
51
71
  @limit ||=
52
- if options.is_a?(Proc)
53
- options.call(response)
54
- elsif options.is_a?(Integer)
55
- options
56
- elsif options.is_a?(Hash) && options[:header]
57
- response.headers[options[:header]]&.to_i
72
+ if options.dig(:limit).is_a?(Proc)
73
+ options.dig(:limit).call(response)
74
+ elsif options.dig(:limit).is_a?(Integer)
75
+ options.dig(:limit)
76
+ elsif options.dig(:limit).is_a?(Hash) && options.dig(:limit, :header) && response.headers
77
+ response.headers[options.dig(:limit, :header)]&.to_i
58
78
  end
59
79
  end
60
80
 
61
- def remaining(options:, response:)
62
- @remaining ||=
63
- begin
64
- if options.is_a?(Proc)
65
- options.call(response)
66
- elsif options.is_a?(Hash) && options[:header]
67
- response.headers[options[:header]]&.to_i
81
+ def remaining
82
+ @remaining ||= begin
83
+ if options.dig(:remaining).is_a?(Proc)
84
+ options.dig(:remaining).call(response)
85
+ elsif options.dig(:remaining).is_a?(Hash) && options.dig(:remaining, :header) && response.headers
86
+ response.headers[options.dig(:remaining, :header)]&.to_i
87
+ elsif options.dig(:remaining).blank?
88
+ remaining_before = self.class.tracker(provider).dig(:remaining) || request.options.dig(:throttle, :limit)
89
+ expires = self.class.tracker(provider).dig(:expires)
90
+ if expires && expires > DateTime.now
91
+ remaining_before - 1
92
+ else
93
+ request.options.dig(:throttle, :limit) - 1
68
94
  end
69
95
  end
96
+ end
70
97
  end
71
98
 
72
- def expires(options:, response:)
73
- @expires ||= convert_expires(read_expire_option(options, response))
74
- end
99
+ def expires
100
+ @expires ||= begin
101
+ if options.dig(:expires).is_a?(ActiveSupport::Duration) && self.class.tracker(provider).dig(:expires).present?
102
+ if self.class.tracker(provider)[:expires] > DateTime.now
103
+ self.class.tracker(provider)[:expires]
104
+ else
105
+ DateTime.now + options.dig(:expires)
106
+ end
107
+ elsif options.dig(:expires).is_a?(Hash) && options.dig(:expires, :header)
75
108
 
76
- def read_expire_option(options, response)
77
- (options.is_a?(Hash) && options[:header]) ? response.headers[options[:header]] : options
109
+ convert_expire_value(response.headers[options.dig(:expires, :header)]) if response.headers
110
+ else
111
+ convert_expire_value(options.dig(:expires))
112
+ end
113
+ end
78
114
  end
79
115
 
80
- def convert_expires(value)
116
+ def convert_expire_value(value)
81
117
  return if value.blank?
82
118
  return value.call(response) if value.is_a?(Proc)
119
+ return DateTime.now + value if value.is_a?(ActiveSupport::Duration)
83
120
  return Time.parse(value) if value.match(/GMT/)
84
121
  Time.zone.at(value.to_i).to_datetime
85
122
  end
data/lib/dhc/logger.rb ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+ require 'forwardable'
5
+
6
+ class DHC::Logger < Logger
7
+ include ActiveSupport::Configurable
8
+ include Singleton
9
+
10
+ config_accessor :logger
11
+
12
+ class << self
13
+ extend Forwardable
14
+ def_delegators :instance, :log, :info, :error, :warn, :debug
15
+ end
16
+
17
+ def initialize(logdev = nil)
18
+ super
19
+ if DHC::Logger.logger
20
+ self.logger = DHC::Logger.logger
21
+ elsif defined? Rails
22
+ self.logger = Rails.logger
23
+ end
24
+ end
25
+
26
+ def self.log(severity, message = nil, progname = nil)
27
+ return if logger.blank?
28
+ logger.log(severity, message, progname)
29
+ end
30
+ end
data/lib/dhc/rspec.rb CHANGED
@@ -6,6 +6,6 @@ RSpec.configure do |config|
6
6
  config.before(:each) do
7
7
  DHC::Caching.cache = ActiveSupport::Cache::MemoryStore.new
8
8
  DHC::Caching.cache.clear
9
- DHC::Throttle.track = nil
9
+ Rails.cache.write(DHC::Throttle::CACHE_KEY, nil) if defined? Rails
10
10
  end
11
11
  end
data/lib/dhc/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DHC
4
- VERSION ||= '2.0.1'
4
+ VERSION ||= '2.2.1'
5
5
  end
data/lib/dhc.rb CHANGED
@@ -72,6 +72,7 @@ module DHC
72
72
  autoload :Response, 'dhc/response'
73
73
  autoload :Rollbar, 'dhc/interceptors/rollbar'
74
74
  autoload :Zipkin, 'dhc/interceptors/zipkin'
75
+ autoload :Logger, 'dhc/logger'
75
76
 
76
77
  require 'dhc/railtie' if defined?(Rails)
77
78
  end
@@ -46,8 +46,8 @@ describe DHC::Caching do
46
46
  it 'serves a response from local cache without trying the central cache' do
47
47
  expect(Rails.cache).to receive(:fetch).at_least(:once).and_call_original
48
48
  expect(Rails.cache).to receive(:write).and_call_original
49
- expect(-> { response_has_been_cached_and_served_from_cache! })
50
- .to output(%{[DHC] served from local cache: "DHC_CACHE(v1): GET http://depay.fi"\n}).to_stdout
49
+ expect(DHC::Logger).to receive(:info).with(%{[DHC] served from local cache: "DHC_CACHE(v1): GET http://depay.fi"}).and_call_original
50
+ response_has_been_cached_and_served_from_cache!
51
51
  end
52
52
  end
53
53
 
@@ -67,8 +67,8 @@ describe DHC::Caching do
67
67
  expect(redis_cache).to receive(:write).and_return(true)
68
68
  expect(Rails.cache).to receive(:fetch).and_call_original
69
69
  expect(Rails.cache).to receive(:write).and_call_original
70
- expect(-> { response_has_been_cached_and_served_from_cache! })
71
- .to output(%{[DHC] served from central cache: "DHC_CACHE(v1): GET http://depay.fi"\n}).to_stdout
70
+ expect(DHC::Logger).to receive(:info).with(%{[DHC] served from central cache: "DHC_CACHE(v1): GET http://depay.fi"}).and_call_original
71
+ response_has_been_cached_and_served_from_cache!
72
72
  end
73
73
  end
74
74
 
@@ -78,8 +78,8 @@ describe DHC::Caching do
78
78
  expect(redis_cache).to receive(:write).and_return(true)
79
79
  expect(Rails.cache).to receive(:fetch).at_least(:once).and_call_original
80
80
  expect(Rails.cache).to receive(:write).and_call_original
81
- expect(-> { response_has_been_cached_and_served_from_cache! })
82
- .to output(%{[DHC] served from local cache: "DHC_CACHE(v1): GET http://depay.fi"\n}).to_stdout
81
+ expect(DHC::Logger).to receive(:info).with(%{[DHC] served from local cache: "DHC_CACHE(v1): GET http://depay.fi"}).and_call_original
82
+ response_has_been_cached_and_served_from_cache!
83
83
  end
84
84
  end
85
85
  end
@@ -97,8 +97,8 @@ describe DHC::Caching do
97
97
  expect(redis_cache).not_to receive(:write)
98
98
  expect(Rails.cache).to receive(:fetch).and_call_original
99
99
  expect(Rails.cache).to receive(:write).and_call_original
100
- expect(-> { response_has_been_cached_and_served_from_cache! })
101
- .to output(%{[DHC] served from central cache: "DHC_CACHE(v1): GET http://depay.fi"\n}).to_stdout
100
+ expect(DHC::Logger).to receive(:info).with(%{[DHC] served from central cache: "DHC_CACHE(v1): GET http://depay.fi"}).and_call_original
101
+ response_has_been_cached_and_served_from_cache!
102
102
  end
103
103
  end
104
104
 
@@ -115,8 +115,8 @@ describe DHC::Caching do
115
115
  expect(redis_cache).to receive(:write).and_return(true)
116
116
  expect(Rails.cache).to receive(:fetch).at_least(:once).and_call_original
117
117
  expect(Rails.cache).to receive(:write).and_call_original
118
- expect(-> { response_has_been_cached_and_served_from_cache! })
119
- .to output(%{[DHC] served from local cache: "DHC_CACHE(v1): GET http://depay.fi"\n}).to_stdout
118
+ expect(DHC::Logger).to receive(:info).with(%{[DHC] served from local cache: "DHC_CACHE(v1): GET http://depay.fi"}).and_call_original
119
+ response_has_been_cached_and_served_from_cache!
120
120
  end
121
121
  end
122
122
 
@@ -132,8 +132,8 @@ describe DHC::Caching do
132
132
  it 'does not inquire the local cache for information neither to write them' do
133
133
  expect(redis_cache).to receive(:fetch).and_return(nil, body: '<h1>Hi there</h1>', code: 200, headers: nil, return_code: nil, mock: :webmock)
134
134
  expect(redis_cache).to receive(:write).and_return(true)
135
- expect(-> { response_has_been_cached_and_served_from_cache! })
136
- .to output(%{[DHC] served from central cache: "DHC_CACHE(v1): GET http://depay.fi"\n}).to_stdout
135
+ expect(DHC::Logger).to receive(:info).with(%{[DHC] served from central cache: "DHC_CACHE(v1): GET http://depay.fi"}).and_call_original
136
+ response_has_been_cached_and_served_from_cache!
137
137
  end
138
138
  end
139
139
  end
@@ -25,8 +25,8 @@ describe DHC::Throttle do
25
25
  end
26
26
 
27
27
  before(:each) do
28
- DHC::Throttle.track = nil
29
28
  DHC.config.interceptors = [DHC::Throttle]
29
+ Rails.cache.write(DHC::Throttle::CACHE_KEY, nil)
30
30
 
31
31
  stub_request(:get, 'http://depay.fi').to_return(
32
32
  headers: { 'limit' => quota_limit, 'remaining' => quota_remaining, 'reset' => quota_reset }
@@ -35,8 +35,8 @@ describe DHC::Throttle do
35
35
 
36
36
  it 'tracks the request limits based on response data' do
37
37
  DHC.get('http://depay.fi', options)
38
- expect(DHC::Throttle.track[provider][:limit]).to eq quota_limit
39
- expect(DHC::Throttle.track[provider][:remaining]).to eq quota_remaining
38
+ expect(Rails.cache.read('DHC/throttle/tracker/v1')[provider][:limit]).to eq quota_limit
39
+ expect(Rails.cache.read('DHC/throttle/tracker/v1')[provider][:remaining]).to eq quota_remaining
40
40
  end
41
41
 
42
42
  context 'fix predefined integer for limit' do
@@ -44,7 +44,7 @@ describe DHC::Throttle do
44
44
 
45
45
  it 'tracks the limit based on initialy provided data' do
46
46
  DHC.get('http://depay.fi', options)
47
- expect(DHC::Throttle.track[provider][:limit]).to eq options_limit
47
+ expect(Rails.cache.read('DHC/throttle/tracker/v1')[provider][:limit]).to eq options_limit
48
48
  end
49
49
  end
50
50
 
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_helper'
4
+
5
+ describe DHC::Throttle do
6
+ let(:options) do
7
+ {
8
+ throttle: {
9
+ provider: provider,
10
+ track: true,
11
+ limit: quota_limit,
12
+ expires: 1.minute,
13
+ break: break_after
14
+ }
15
+ }
16
+ end
17
+
18
+ let(:provider) { 'depay.fi' }
19
+ let(:quota_limit) { 100 }
20
+ let(:break_after) { '80%' }
21
+
22
+ before(:each) do
23
+ DHC.config.interceptors = [DHC::Throttle]
24
+ Rails.cache.write(DHC::Throttle::CACHE_KEY, nil)
25
+
26
+ stub_request(:get, 'http://depay.fi').to_return(status: 200)
27
+ end
28
+
29
+ it 'tracks the request limits based on response data' do
30
+ DHC.get('http://depay.fi', options)
31
+ expect(Rails.cache.read('DHC/throttle/tracker/v1')[provider][:limit]).to eq 100
32
+ expect(Rails.cache.read('DHC/throttle/tracker/v1')[provider][:remaining]).to eq quota_limit - 1
33
+ end
34
+
35
+ context 'breaks' do
36
+ let(:quota_limit) { 100 }
37
+ let(:break_after) { '79%' }
38
+
39
+ it 'hit the breaks if throttling quota is reached' do
40
+ 79.times do
41
+ DHC.get('http://depay.fi', options)
42
+ end
43
+ expect { DHC.get('http://depay.fi', options) }.to raise_error(
44
+ DHC::Throttle::OutOfQuota,
45
+ 'Reached predefined quota for depay.fi'
46
+ )
47
+ end
48
+
49
+ context 'still within quota' do
50
+ let(:break_after) { '80%' }
51
+
52
+ it 'does not hit the breaks' do
53
+ 80.times do
54
+ DHC.get('http://depay.fi', options)
55
+ end
56
+ end
57
+
58
+ it 'does hit the breaks surpassing quota' do
59
+ 80.times do
60
+ DHC.get('http://depay.fi', options)
61
+ end
62
+ expect { DHC.get('http://depay.fi', options) }.to raise_error(
63
+ DHC::Throttle::OutOfQuota,
64
+ 'Reached predefined quota for depay.fi'
65
+ )
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'expires' do
71
+ let(:break_after) { '80%' }
72
+ let(:quota_limit) { 100 }
73
+
74
+ it 'attempts another request if the quota expired' do
75
+ 80.times do
76
+ DHC.get('http://depay.fi', options)
77
+ end
78
+ expect { DHC.get('http://depay.fi', options) }.to raise_error(
79
+ DHC::Throttle::OutOfQuota,
80
+ 'Reached predefined quota for depay.fi'
81
+ )
82
+ Timecop.travel(Time.zone.now + 1.minute)
83
+ 80.times do
84
+ DHC.get('http://depay.fi', options)
85
+ end
86
+ expect { DHC.get('http://depay.fi', options) }.to raise_error(
87
+ DHC::Throttle::OutOfQuota,
88
+ 'Reached predefined quota for depay.fi'
89
+ )
90
+ end
91
+ end
92
+
93
+ context 'multiple provider' do
94
+ it 'tracks multiple providers without a problem' do
95
+ DHC.get('http://depay.fi', options)
96
+ stub_request(:get, 'http://depay.app').to_return(status: 200)
97
+ DHC.get('http://depay.app', {
98
+ throttle: {
99
+ provider: 'depay.app',
100
+ track: true,
101
+ limit: quota_limit,
102
+ expires: 1.minute,
103
+ break: break_after
104
+ }
105
+ })
106
+ expect(Rails.cache.read('DHC/throttle/tracker/v1')['depay.fi']).to be_present
107
+ expect(Rails.cache.read('DHC/throttle/tracker/v1')['depay.app']).to be_present
108
+ end
109
+ end
110
+ end
@@ -23,7 +23,6 @@ describe DHC::Throttle do
23
23
  let(:expires_in) { (Time.zone.now + 1.hour).to_i }
24
24
 
25
25
  before(:each) do
26
- DHC::Throttle.track = nil
27
26
  DHC.config.interceptors = [DHC::Throttle]
28
27
 
29
28
  stub_request(:get, 'http://depay.fi')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dhc
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - https://github.com/DePayFi/dhc/contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-14 00:00:00.000000000 Z
11
+ date: 2021-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -87,6 +87,9 @@ dependencies:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '5.2'
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '7'
90
93
  type: :development
91
94
  prerelease: false
92
95
  version_requirements: !ruby/object:Gem::Requirement
@@ -94,6 +97,9 @@ dependencies:
94
97
  - - ">="
95
98
  - !ruby/object:Gem::Version
96
99
  version: '5.2'
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: '7'
97
103
  - !ruby/object:Gem::Dependency
98
104
  name: redis
99
105
  requirement: !ruby/object:Gem::Requirement
@@ -231,6 +237,7 @@ files:
231
237
  - lib/dhc/interceptors/rollbar.rb
232
238
  - lib/dhc/interceptors/throttle.rb
233
239
  - lib/dhc/interceptors/zipkin.rb
240
+ - lib/dhc/logger.rb
234
241
  - lib/dhc/railtie.rb
235
242
  - lib/dhc/request.rb
236
243
  - lib/dhc/response.rb
@@ -338,6 +345,7 @@ files:
338
345
  - spec/interceptors/rollbar/invalid_encoding_spec.rb
339
346
  - spec/interceptors/rollbar/main_spec.rb
340
347
  - spec/interceptors/throttle/main_spec.rb
348
+ - spec/interceptors/throttle/manually_spec.rb
341
349
  - spec/interceptors/throttle/reset_track_spec.rb
342
350
  - spec/interceptors/zipkin/distributed_tracing_spec.rb
343
351
  - spec/rails_helper.rb
@@ -492,6 +500,7 @@ test_files:
492
500
  - spec/interceptors/rollbar/invalid_encoding_spec.rb
493
501
  - spec/interceptors/rollbar/main_spec.rb
494
502
  - spec/interceptors/throttle/main_spec.rb
503
+ - spec/interceptors/throttle/manually_spec.rb
495
504
  - spec/interceptors/throttle/reset_track_spec.rb
496
505
  - spec/interceptors/zipkin/distributed_tracing_spec.rb
497
506
  - spec/rails_helper.rb