network_resiliency 0.6.9 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8380eb51ca287984c7460bcaec21486e9f3b0d659a4938d9d8acba847408455e
4
- data.tar.gz: 6af73756043d429bbda699f6424385c51487433f759db9a7f5e4e669edfbbd53
3
+ metadata.gz: 0b05ddc43d74cc05325b32b3a45cbc1377bee1228c2c2f8ad7f2fd717ed7b49f
4
+ data.tar.gz: 8a9b5274e52a3ebc039f00e4aad18af9a7c2e645a7a246fd9e45cc474bbfb50b
5
5
  SHA512:
6
- metadata.gz: 0e926bdcfba052de25ae2556478262ffebc6f484eb7dfd7cc6c2ba718128ba6b2bc8a0327f24a9b1e1a2a6cbf5130ed614465dcb3d79092918d7ae47741a9581
7
- data.tar.gz: 7a08743fe845c881e80124f8869d82563419ced41adb68ab654e3aad96d88ca5d6b70ae5dace10135a078652207605a7f4df8c39648f9b0a05e700602da78a5b
6
+ metadata.gz: ffe3b488a66c2721a25a3a995a007ff89a822d4ea2b85638b370535a4895968c5e74084ef89ee7a9bc97a325beba410f74e4ce2ecf4c941e99b00bc3f07daf4a
7
+ data.tar.gz: 5632e5111b856b1fc9d34b31f8d099b584491dbb9beb623ddcff016a058b8f839900fe65554ef60619930843b5b98c4137b92f15722c5040547632b91ec5ac7e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ### v0.7.0 (2023-12-11)
2
+ - proc support for mode
3
+ - rails adapater and deadline
4
+
1
5
  ### v0.6.9 (2023-12-07)
2
6
  - tag mode
3
7
  - request timeout header
data/Gemfile.lock CHANGED
@@ -1,14 +1,95 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- network_resiliency (0.6.9)
4
+ network_resiliency (0.7.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ actioncable (7.1.2)
10
+ actionpack (= 7.1.2)
11
+ activesupport (= 7.1.2)
12
+ nio4r (~> 2.0)
13
+ websocket-driver (>= 0.6.1)
14
+ zeitwerk (~> 2.6)
15
+ actionmailbox (7.1.2)
16
+ actionpack (= 7.1.2)
17
+ activejob (= 7.1.2)
18
+ activerecord (= 7.1.2)
19
+ activestorage (= 7.1.2)
20
+ activesupport (= 7.1.2)
21
+ mail (>= 2.7.1)
22
+ net-imap
23
+ net-pop
24
+ net-smtp
25
+ actionmailer (7.1.2)
26
+ actionpack (= 7.1.2)
27
+ actionview (= 7.1.2)
28
+ activejob (= 7.1.2)
29
+ activesupport (= 7.1.2)
30
+ mail (~> 2.5, >= 2.5.4)
31
+ net-imap
32
+ net-pop
33
+ net-smtp
34
+ rails-dom-testing (~> 2.2)
35
+ actionpack (7.1.2)
36
+ actionview (= 7.1.2)
37
+ activesupport (= 7.1.2)
38
+ nokogiri (>= 1.8.5)
39
+ racc
40
+ rack (>= 2.2.4)
41
+ rack-session (>= 1.0.1)
42
+ rack-test (>= 0.6.3)
43
+ rails-dom-testing (~> 2.2)
44
+ rails-html-sanitizer (~> 1.6)
45
+ actiontext (7.1.2)
46
+ actionpack (= 7.1.2)
47
+ activerecord (= 7.1.2)
48
+ activestorage (= 7.1.2)
49
+ activesupport (= 7.1.2)
50
+ globalid (>= 0.6.0)
51
+ nokogiri (>= 1.8.5)
52
+ actionview (7.1.2)
53
+ activesupport (= 7.1.2)
54
+ builder (~> 3.1)
55
+ erubi (~> 1.11)
56
+ rails-dom-testing (~> 2.2)
57
+ rails-html-sanitizer (~> 1.6)
58
+ activejob (7.1.2)
59
+ activesupport (= 7.1.2)
60
+ globalid (>= 0.3.6)
61
+ activemodel (7.1.2)
62
+ activesupport (= 7.1.2)
63
+ activerecord (7.1.2)
64
+ activemodel (= 7.1.2)
65
+ activesupport (= 7.1.2)
66
+ timeout (>= 0.4.0)
67
+ activestorage (7.1.2)
68
+ actionpack (= 7.1.2)
69
+ activejob (= 7.1.2)
70
+ activerecord (= 7.1.2)
71
+ activesupport (= 7.1.2)
72
+ marcel (~> 1.0)
73
+ activesupport (7.1.2)
74
+ base64
75
+ bigdecimal
76
+ concurrent-ruby (~> 1.0, >= 1.0.2)
77
+ connection_pool (>= 2.2.5)
78
+ drb
79
+ i18n (>= 1.6, < 2)
80
+ minitest (>= 5.1)
81
+ mutex_m
82
+ tzinfo (~> 2.0)
83
+ base64 (0.2.0)
84
+ bigdecimal (3.1.4)
85
+ builder (3.2.4)
9
86
  byebug (11.1.3)
87
+ concurrent-ruby (1.2.2)
88
+ connection_pool (2.4.1)
89
+ crass (1.0.6)
10
90
  datadog-ci (0.2.0)
11
91
  msgpack
92
+ date (3.3.4)
12
93
  ddtrace (1.15.0)
13
94
  datadog-ci (~> 0.2.0)
14
95
  debase-ruby_core_source (= 3.2.2)
@@ -19,6 +100,9 @@ GEM
19
100
  diff-lcs (1.5.0)
20
101
  docile (1.4.0)
21
102
  dogstatsd-ruby (4.8.3)
103
+ drb (2.2.0)
104
+ ruby2_keywords
105
+ erubi (1.12.0)
22
106
  faraday (1.10.3)
23
107
  faraday-em_http (~> 1.0)
24
108
  faraday-em_synchrony (~> 1.0)
@@ -43,17 +127,93 @@ GEM
43
127
  faraday-rack (1.0.0)
44
128
  faraday-retry (1.0.3)
45
129
  ffi (1.16.3)
130
+ globalid (1.2.1)
131
+ activesupport (>= 6.1)
132
+ i18n (1.14.1)
133
+ concurrent-ruby (~> 1.0)
134
+ io-console (0.6.0)
135
+ irb (1.10.1)
136
+ rdoc
137
+ reline (>= 0.3.8)
46
138
  libdatadog (5.0.0.1.0)
47
139
  libddwaf (1.14.0.0.0)
48
140
  ffi (~> 1.0)
141
+ loofah (2.22.0)
142
+ crass (~> 1.0.2)
143
+ nokogiri (>= 1.12.0)
144
+ mail (2.8.1)
145
+ mini_mime (>= 0.1.1)
146
+ net-imap
147
+ net-pop
148
+ net-smtp
149
+ marcel (1.0.2)
150
+ mini_mime (1.1.5)
151
+ mini_portile2 (2.8.5)
152
+ minitest (5.20.0)
49
153
  msgpack (1.7.2)
50
154
  multipart-post (2.3.0)
155
+ mutex_m (0.2.0)
51
156
  mysql2 (0.5.5)
157
+ net-imap (0.4.7)
158
+ date
159
+ net-protocol
160
+ net-pop (0.1.2)
161
+ net-protocol
162
+ net-protocol (0.2.2)
163
+ timeout
164
+ net-smtp (0.4.0)
165
+ net-protocol
166
+ nio4r (2.7.0)
167
+ nokogiri (1.15.5)
168
+ mini_portile2 (~> 2.8.2)
169
+ racc (~> 1.4)
52
170
  pg (1.5.4)
171
+ psych (5.1.1.1)
172
+ stringio
173
+ racc (1.7.3)
53
174
  rack (3.0.8)
175
+ rack-session (2.0.0)
176
+ rack (>= 3.0.0)
54
177
  rack-test (2.1.0)
55
178
  rack (>= 1.3)
179
+ rackup (2.1.0)
180
+ rack (>= 3)
181
+ webrick (~> 1.8)
182
+ rails (7.1.2)
183
+ actioncable (= 7.1.2)
184
+ actionmailbox (= 7.1.2)
185
+ actionmailer (= 7.1.2)
186
+ actionpack (= 7.1.2)
187
+ actiontext (= 7.1.2)
188
+ actionview (= 7.1.2)
189
+ activejob (= 7.1.2)
190
+ activemodel (= 7.1.2)
191
+ activerecord (= 7.1.2)
192
+ activestorage (= 7.1.2)
193
+ activesupport (= 7.1.2)
194
+ bundler (>= 1.15.0)
195
+ railties (= 7.1.2)
196
+ rails-dom-testing (2.2.0)
197
+ activesupport (>= 5.0.0)
198
+ minitest
199
+ nokogiri (>= 1.6)
200
+ rails-html-sanitizer (1.6.0)
201
+ loofah (~> 2.21)
202
+ nokogiri (~> 1.14)
203
+ railties (7.1.2)
204
+ actionpack (= 7.1.2)
205
+ activesupport (= 7.1.2)
206
+ irb
207
+ rackup (>= 1.0.0)
208
+ rake (>= 12.2)
209
+ thor (~> 1.0, >= 1.2.2)
210
+ zeitwerk (~> 2.6)
211
+ rake (13.1.0)
212
+ rdoc (6.6.1)
213
+ psych (>= 4.0.0)
56
214
  redis (4.8.1)
215
+ reline (0.4.1)
216
+ io-console (~> 0.5)
57
217
  rspec (3.12.0)
58
218
  rspec-core (~> 3.12.0)
59
219
  rspec-expectations (~> 3.12.0)
@@ -66,6 +226,14 @@ GEM
66
226
  rspec-mocks (3.12.6)
67
227
  diff-lcs (>= 1.2.0, < 2.0)
68
228
  rspec-support (~> 3.12.0)
229
+ rspec-rails (6.1.0)
230
+ actionpack (>= 6.1)
231
+ activesupport (>= 6.1)
232
+ railties (>= 6.1)
233
+ rspec-core (~> 3.12)
234
+ rspec-expectations (~> 3.12)
235
+ rspec-mocks (~> 3.12)
236
+ rspec-support (~> 3.12)
69
237
  rspec-support (3.12.1)
70
238
  ruby2_keywords (0.0.5)
71
239
  simplecov (0.22.0)
@@ -74,6 +242,17 @@ GEM
74
242
  simplecov_json_formatter (~> 0.1)
75
243
  simplecov-html (0.12.3)
76
244
  simplecov_json_formatter (0.1.4)
245
+ stringio (3.1.0)
246
+ thor (1.3.0)
247
+ timecop (0.9.8)
248
+ timeout (0.4.1)
249
+ tzinfo (2.0.6)
250
+ concurrent-ruby (~> 1.0)
251
+ webrick (1.8.1)
252
+ websocket-driver (0.7.6)
253
+ websocket-extensions (>= 0.1.0)
254
+ websocket-extensions (0.1.5)
255
+ zeitwerk (2.6.12)
77
256
 
78
257
  PLATFORMS
79
258
  ruby
@@ -89,9 +268,12 @@ DEPENDENCIES
89
268
  pg (~> 1.1)
90
269
  rack
91
270
  rack-test
271
+ rails (>= 5)
92
272
  redis (~> 4)
93
273
  rspec
274
+ rspec-rails
94
275
  simplecov
276
+ timecop
95
277
 
96
278
  BUNDLED WITH
97
279
  2.4.20
@@ -5,6 +5,13 @@ module NetworkResiliency
5
5
  module HTTP
6
6
  extend self
7
7
 
8
+ ERRORS = [
9
+ Timeout::Error,
10
+ IOError,
11
+ SystemCallError,
12
+ (OpenSSL::OpenSSLError if defined?(OpenSSL::SSL)),
13
+ ].compact
14
+
8
15
  REQUEST_TIMEOUT_HEADER = "X-Request-Timeout"
9
16
 
10
17
  def patch(instance = nil)
@@ -41,8 +48,8 @@ module NetworkResiliency
41
48
  end
42
49
 
43
50
  timeouts = NetworkResiliency.timeouts_for(
44
- adapter: "http",
45
- action: action.to_s,
51
+ adapter: :http,
52
+ action: action,
46
53
  destination: destination,
47
54
  max: original_timeout,
48
55
  units: :seconds,
@@ -67,10 +74,7 @@ module NetworkResiliency
67
74
  set_timeout.call(timeout)
68
75
 
69
76
  yield timeout
70
- rescue ::Timeout::Error,
71
- defined?(OpenSSL::SSL) ? OpenSSL::OpenSSLError : IOError,
72
- SystemCallError => e
73
-
77
+ rescue *ERRORS => e
74
78
  # capture error
75
79
  error = e.class
76
80
 
@@ -83,8 +87,8 @@ module NetworkResiliency
83
87
  self.max_retries = original_max_retries
84
88
 
85
89
  NetworkResiliency.record(
86
- adapter: "http",
87
- action: action.to_s,
90
+ adapter: :http,
91
+ action: action,
88
92
  destination: destination,
89
93
  duration: ts,
90
94
  error: error,
@@ -31,8 +31,8 @@ module NetworkResiliency
31
31
  ts += NetworkResiliency.timestamp
32
32
 
33
33
  NetworkResiliency.record(
34
- adapter: "mysql",
35
- action: "connect",
34
+ adapter: :mysql,
35
+ action: :connect,
36
36
  destination: host,
37
37
  error: e&.class,
38
38
  duration: ts,
@@ -33,8 +33,8 @@ module NetworkResiliency
33
33
  ts += NetworkResiliency.timestamp
34
34
 
35
35
  NetworkResiliency.record(
36
- adapter: "postgres",
37
- action: "connect",
36
+ adapter: :postgres,
37
+ action: :connect,
38
38
  destination: host,
39
39
  error: e&.class,
40
40
  duration: ts,
@@ -0,0 +1,48 @@
1
+ gem "rails", ">= 5"
2
+ require "rails"
3
+
4
+ module NetworkResiliency
5
+ module Adapter
6
+ module Rails
7
+ extend self
8
+
9
+ def patch(instance = nil)
10
+ instance ||= ::Rails.application
11
+
12
+ unless instance.is_a?(::Rails::Application)
13
+ raise ArgumentError, "expected Rails::Application instance, found: #{instance}"
14
+ end
15
+
16
+ return if patched?(instance)
17
+
18
+ instance.config.middleware.use Middleware
19
+ end
20
+
21
+ def patched?(instance = nil)
22
+ instance ||= ::Rails.application
23
+
24
+ return false unless instance.initialized?
25
+
26
+ instance.config.middleware.include?(Middleware)
27
+ end
28
+
29
+ class Middleware
30
+ def initialize(app)
31
+ @app = app
32
+ end
33
+
34
+ def call(env)
35
+ header = HTTP::REQUEST_TIMEOUT_HEADER.upcase.tr('-', '_')
36
+ timeout = env["HTTP_#{header}"]&.to_f
37
+
38
+ NetworkResiliency.deadline = timeout if timeout
39
+
40
+ @app.call(env)
41
+ ensure
42
+ NetworkResiliency.deadline = nil
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+
@@ -61,8 +61,8 @@ module NetworkResiliency
61
61
  original_timeout = @options[timeout_key]
62
62
 
63
63
  timeouts = NetworkResiliency.timeouts_for(
64
- adapter: "redis",
65
- action: action.to_s,
64
+ adapter: :redis,
65
+ action: action,
66
66
  destination: destination,
67
67
  max: @options[timeout_key],
68
68
  units: :seconds,
@@ -101,8 +101,8 @@ module NetworkResiliency
101
101
  @options[timeout_key] = original_timeout
102
102
 
103
103
  NetworkResiliency.record(
104
- adapter: "redis",
105
- action: action.to_s,
104
+ adapter: :redis,
105
+ action: action,
106
106
  destination: destination,
107
107
  duration: ts,
108
108
  error: error,
@@ -1,3 +1,3 @@
1
1
  module NetworkResiliency
2
- VERSION = "0.6.9"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -13,10 +13,11 @@ module NetworkResiliency
13
13
  autoload :Redis, "network_resiliency/adapter/redis"
14
14
  autoload :Mysql, "network_resiliency/adapter/mysql"
15
15
  autoload :Postgres, "network_resiliency/adapter/postgres"
16
+ autoload :Rails, "network_resiliency/adapter/rails"
16
17
  end
17
18
 
18
19
  ACTIONS = [ :connect, :request ].freeze
19
- ADAPTERS = [ :http, :faraday, :redis, :mysql, :postgres ].freeze
20
+ ADAPTERS = [ :http, :faraday, :redis, :mysql, :postgres, :rails ].freeze
20
21
  MODE = [ :observe, :resilient ].freeze
21
22
  RESILIENCY_SIZE_THRESHOLD = 1_000
22
23
 
@@ -49,6 +50,8 @@ module NetworkResiliency
49
50
  Adapter::Mysql.patch
50
51
  when :postgres
51
52
  Adapter::Postgres.patch
53
+ when :rails
54
+ Adapter::Rails.patch
52
55
  else
53
56
  raise NotImplementedError
54
57
  end
@@ -108,13 +111,38 @@ module NetworkResiliency
108
111
  raise ArgumentError, "invalid NetworkResiliency action: #{action}"
109
112
  end
110
113
 
111
- (@mode && @mode[action]) || :observe
114
+ mode = if @mode.is_a?(Proc)
115
+ @mode.call(action)
116
+ elsif @mode
117
+ @mode[action]
118
+ end || :observe
119
+
120
+ unless MODE.include?(mode)
121
+ raise ArgumentError, "invalid NetworkResiliency mode: #{mode}"
122
+ end
123
+
124
+ mode
125
+ rescue => e
126
+ NetworkResiliency.statsd&.increment(
127
+ "network_resiliency.error",
128
+ tags: {
129
+ method: __method__,
130
+ type: e.class,
131
+ },
132
+ )
133
+
134
+ warn "[ERROR] NetworkResiliency: #{e.class}: #{e.message}"
135
+
136
+ :observe
112
137
  end
113
138
 
114
139
  def mode=(mode)
115
140
  @mode = {}
116
141
 
117
- if mode.is_a?(Hash)
142
+ case mode
143
+ when Proc
144
+ @mode = mode
145
+ when Hash
118
146
  invalid = mode.keys - ACTIONS
119
147
 
120
148
  unless invalid.empty?
@@ -139,6 +167,25 @@ module NetworkResiliency
139
167
  @mode.freeze
140
168
  end
141
169
 
170
+ def deadline
171
+ thread_state["deadline"]
172
+ end
173
+
174
+ def deadline=(ts)
175
+ thread_state["deadline"] = case ts
176
+ when Numeric
177
+ Time.now + ts
178
+ when Time
179
+ ts
180
+ when nil
181
+ nil
182
+ else
183
+ raise ArgumentError, "invalid deadline: #{ts}"
184
+ end
185
+
186
+ # warn or raise if we're already past the deadline?
187
+ end
188
+
142
189
  def normalize_request(adapter, request = nil, **context, &block)
143
190
  unless ADAPTERS.include?(adapter)
144
191
  raise ArgumentError, "invalid adapter: #{adapter}"
@@ -177,7 +224,7 @@ module NetworkResiliency
177
224
  adapter: adapter,
178
225
  destination: destination,
179
226
  error: error,
180
- mode: mode(action.to_sym),
227
+ mode: mode(action),
181
228
  attempts: (attempts if attempts > 1),
182
229
  }.compact,
183
230
  )
@@ -22,7 +22,10 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency "pg", "~> 1.1"
23
23
  s.add_development_dependency "rack"
24
24
  s.add_development_dependency "rack-test"
25
+ s.add_development_dependency "rails", ">= 5"
25
26
  s.add_development_dependency "redis", "~> 4"
26
27
  s.add_development_dependency "rspec"
28
+ s.add_development_dependency "rspec-rails"
27
29
  s.add_development_dependency "simplecov"
30
+ s.add_development_dependency "timecop"
28
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: network_resiliency
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.9
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Pepper
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-07 00:00:00.000000000 Z
11
+ date: 2023-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -136,6 +136,20 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rails
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '5'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '5'
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: redis
141
155
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +178,20 @@ dependencies:
164
178
  - - ">="
165
179
  - !ruby/object:Gem::Version
166
180
  version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rspec-rails
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
167
195
  - !ruby/object:Gem::Dependency
168
196
  name: simplecov
169
197
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +206,20 @@ dependencies:
178
206
  - - ">="
179
207
  - !ruby/object:Gem::Version
180
208
  version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: timecop
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
181
223
  description: "..."
182
224
  email:
183
225
  executables: []
@@ -194,6 +236,7 @@ files:
194
236
  - lib/network_resiliency/adapter/http.rb
195
237
  - lib/network_resiliency/adapter/mysql.rb
196
238
  - lib/network_resiliency/adapter/postgres.rb
239
+ - lib/network_resiliency/adapter/rails.rb
197
240
  - lib/network_resiliency/adapter/redis.rb
198
241
  - lib/network_resiliency/refinements.rb
199
242
  - lib/network_resiliency/stats.rb