network_resiliency 0.0.2 → 0.1.1

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: d085dba12da295ad4c4bb4d540acb3b865c8d8486b9bdf6d812e74430efcd55f
4
- data.tar.gz: 24d61f1205ecba15f7acbda327d91be3ca0c74dd0955c2fe03338f873435d478
3
+ metadata.gz: 1b75b4aad26c41942f4d38ad70abb82d8f098eb377e9e5f44d1f6dde41ab6225
4
+ data.tar.gz: 47c899a650d66cea1117743ce4b53ee7bc50cc4fef8dfca3337aa071d0f81964
5
5
  SHA512:
6
- metadata.gz: 91e9bcd5141345e0117be83f1e01951a11f6ffc8b100c1776a0ba3a2ac2bde19642369875ee79d995f8c4f3bbc0742f72c67102295bdecb2e9afd681597f555c
7
- data.tar.gz: df13161c53527c10143d7c11b56ac7cc2a75189eb58b2d698d2f9940dd50a894a3e6dae8680764a6773c68c6dc107faf8613b457c5edeb1dc7c65200fe97e491
6
+ metadata.gz: ef7d805366f84daf7a27f5fb6dc88ef846741456203fa23f30512d780ae46065b5519caa474e7750b260e2a9bca5b9e296cb4def7e60402cfabdf0ae4aa1bf7c
7
+ data.tar.gz: 11d564818a9700a685c8d3dc9873de64181079fffffcbc0dd192d2ddbb47f0b75e43e92ba08d4523376a0a617ba60c9dd599e07fce1c055e48398b38f2e40ee3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ### v0.1.1 (2023-09-27)
2
+ - prevent double patching
3
+ - filter ip addresses
4
+ - simplify
5
+ - configure
6
+
7
+ ### v0.1.0 (2023-09-26)
8
+ - rework faraday adapter
9
+ - faraday
10
+ - adapter scoped enabled
11
+ - scope rspec helper
12
+ - adapter tag
13
+ - enable disable block mode
14
+ - drop ruby 2.7 support
15
+ - resiliency
16
+ - pointer
17
+ - code coverage upgrade
18
+ - requirements
19
+ - http adapter
20
+ - mock http server
21
+ - add ddtrace to dev
22
+
1
23
  ### v0.0.2 (2023-05-09)
2
24
  - rename to Network Resiliency
3
25
  - fix sample variance
data/Gemfile.lock CHANGED
@@ -1,67 +1,90 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- network_resiliency (0.0.2)
5
- faraday
4
+ network_resiliency (0.1.1)
6
5
 
7
6
  GEM
8
7
  remote: https://rubygems.org/
9
8
  specs:
10
9
  byebug (11.1.3)
11
- codecov (0.5.2)
12
- simplecov (>= 0.15, < 0.22)
13
- connection_pool (2.3.0)
14
- diff-lcs (1.4.4)
10
+ ddtrace (1.14.0)
11
+ debase-ruby_core_source (= 3.2.1)
12
+ libdatadog (~> 3.0.0.1.0)
13
+ libddwaf (~> 1.9.0.0.0)
14
+ msgpack
15
+ debase-ruby_core_source (3.2.1)
16
+ diff-lcs (1.5.0)
15
17
  docile (1.4.0)
16
- faraday (2.7.4)
17
- faraday-net_http (>= 2.0, < 3.1)
18
+ dogstatsd-ruby (4.8.3)
19
+ faraday (1.10.3)
20
+ faraday-em_http (~> 1.0)
21
+ faraday-em_synchrony (~> 1.0)
22
+ faraday-excon (~> 1.1)
23
+ faraday-httpclient (~> 1.0)
24
+ faraday-multipart (~> 1.0)
25
+ faraday-net_http (~> 1.0)
26
+ faraday-net_http_persistent (~> 1.0)
27
+ faraday-patron (~> 1.0)
28
+ faraday-rack (~> 1.0)
29
+ faraday-retry (~> 1.0)
18
30
  ruby2_keywords (>= 0.0.4)
19
- faraday-net_http (3.0.2)
31
+ faraday-em_http (1.0.0)
32
+ faraday-em_synchrony (1.0.0)
33
+ faraday-excon (1.1.0)
34
+ faraday-httpclient (1.0.1)
35
+ faraday-multipart (1.0.4)
36
+ multipart-post (~> 2)
37
+ faraday-net_http (1.0.1)
38
+ faraday-net_http_persistent (1.2.0)
39
+ faraday-patron (1.0.0)
20
40
  faraday-rack (1.0.0)
21
- rack (3.0.2)
22
- rack-test (2.0.2)
41
+ faraday-retry (1.0.3)
42
+ ffi (1.15.5)
43
+ libdatadog (3.0.0.1.0)
44
+ libddwaf (1.9.0.0.1)
45
+ ffi (~> 1.0)
46
+ msgpack (1.7.2)
47
+ multipart-post (2.3.0)
48
+ rack (3.0.8)
49
+ rack-test (2.1.0)
23
50
  rack (>= 1.3)
24
- redis (5.0.5)
25
- redis-client (>= 0.9.0)
26
- redis-client (0.11.2)
27
- connection_pool
28
- rspec (3.10.0)
29
- rspec-core (~> 3.10.0)
30
- rspec-expectations (~> 3.10.0)
31
- rspec-mocks (~> 3.10.0)
32
- rspec-core (3.10.1)
33
- rspec-support (~> 3.10.0)
34
- rspec-expectations (3.10.1)
51
+ redis (4.8.1)
52
+ rspec (3.12.0)
53
+ rspec-core (~> 3.12.0)
54
+ rspec-expectations (~> 3.12.0)
55
+ rspec-mocks (~> 3.12.0)
56
+ rspec-core (3.12.2)
57
+ rspec-support (~> 3.12.0)
58
+ rspec-expectations (3.12.3)
35
59
  diff-lcs (>= 1.2.0, < 2.0)
36
- rspec-support (~> 3.10.0)
37
- rspec-mocks (3.10.2)
60
+ rspec-support (~> 3.12.0)
61
+ rspec-mocks (3.12.6)
38
62
  diff-lcs (>= 1.2.0, < 2.0)
39
- rspec-support (~> 3.10.0)
40
- rspec-support (3.10.2)
63
+ rspec-support (~> 3.12.0)
64
+ rspec-support (3.12.1)
41
65
  ruby2_keywords (0.0.5)
42
- simplecov (0.21.2)
66
+ simplecov (0.22.0)
43
67
  docile (~> 1.1)
44
68
  simplecov-html (~> 0.11)
45
69
  simplecov_json_formatter (~> 0.1)
46
70
  simplecov-html (0.12.3)
47
- simplecov_json_formatter (0.1.3)
71
+ simplecov_json_formatter (0.1.4)
48
72
 
49
73
  PLATFORMS
50
- x86_64-darwin-19
51
- x86_64-darwin-20
52
- x86_64-darwin-21
74
+ ruby
53
75
 
54
76
  DEPENDENCIES
55
77
  byebug
56
- codecov
78
+ ddtrace (>= 1)
79
+ dogstatsd-ruby (<= 4.8.3)
80
+ faraday (~> 1)
57
81
  faraday-rack
58
82
  network_resiliency!
59
83
  rack
60
84
  rack-test
61
- redis
62
- redis-client (>= 0.10)
85
+ redis (~> 4)
63
86
  rspec
64
87
  simplecov
65
88
 
66
89
  BUNDLED WITH
67
- 2.2.20
90
+ 2.4.19
data/README.md CHANGED
@@ -1,6 +1,11 @@
1
- ApiAvenger
1
+ NetworkResiliency
2
2
  ======
3
- ...
3
+ ![Gem](https://img.shields.io/gem/dt/network_resiliency?style=plastic)
4
+ [![codecov](https://codecov.io/gh/dpep/network_resiliency_rb/branch/main/graph/badge.svg)](https://codecov.io/gh/dpep/network_resiliency_rb)
5
+
6
+ Making networks more resilient to errors.
7
+
8
+ Resiliency: the ability to recover from adversity or adjust to change.
4
9
 
5
10
 
6
11
  ```ruby
@@ -21,6 +26,10 @@ Yes please :)
21
26
  1. Create a Pull Request
22
27
 
23
28
 
29
+
24
30
  ----
25
- ![Gem](https://img.shields.io/gem/dt/network_resiliency?style=plastic)
26
- [![codecov](https://codecov.io/gh/dpep/network_resiliency_rb/branch/main/graph/badge.svg)](https://codecov.io/gh/dpep/network_resiliency_rb)
31
+ ### Inspired by
32
+
33
+ https://github.com/lostisland/faraday-retry/blob/main/lib/faraday/retry/middleware.rb
34
+
35
+ https://github.com/ankane/the-ultimate-guide-to-ruby-timeouts
@@ -2,58 +2,18 @@ require "faraday"
2
2
 
3
3
  module NetworkResiliency
4
4
  module Adapter
5
- class Faraday < ::Faraday::Middleware
6
- def call(env)
7
- puts "NetworkResiliency called: #{env.url}"
8
- # env.options.timeout = 0.001
9
- # open_timeout
10
-
11
- # url => id
12
- # predict time
13
- # get dynamic timeout
14
-
15
- if NetworkResiliency.enabled?
16
- # temp update timeout
17
- # with_timeout(...) { super }
18
- else
19
- super
5
+ class Faraday < ::Faraday::Adapter::NetHttp
6
+ def build_connection(env)
7
+ super.tap do |conn|
8
+ unless NetworkResiliency::Adapter::HTTP.patched?(conn)
9
+ NetworkResiliency::Adapter::HTTP.patch(conn)
10
+ end
20
11
  end
21
- rescue ::Faraday::Error => e
22
- # note exception for ensure block
23
- ensure
24
- # record time taken
25
-
26
- # reraise if applicable
27
- raise e if e
28
- end
29
-
30
- def normalized_id(env)
31
- env.url
32
- end
33
-
34
- def with_timeout(env, timeout)
35
- old_timeouts = [
36
- env.options.timeout,
37
- env.options.open_timeout,
38
- env.options.read_timeout,
39
- env.options.write_timeout,
40
- ]
41
-
42
- env.options.timeout = [
43
- env.options.timeout,
44
- timeout,
45
- ].compact.min
46
-
47
- # env.options.open_timeout = [ env.options.open_timeout, timeout ].compact.min
48
- # ...
49
- ensure
50
- env.options.timeout = old_timeouts[0]
51
- # ...
52
12
  end
53
13
  end
54
14
  end
55
15
  end
56
16
 
57
- Faraday::Request.register_middleware(
17
+ Faraday::Adapter.register_middleware(
58
18
  network_resiliency: NetworkResiliency::Adapter::Faraday,
59
19
  )
@@ -0,0 +1,42 @@
1
+ require "net/http"
2
+
3
+ module NetworkResiliency
4
+ module Adapter
5
+ module HTTP
6
+ extend self
7
+
8
+ def patch(instance = nil)
9
+ (instance&.singleton_class || Net::HTTP).prepend(Instrumentation)
10
+ end
11
+
12
+ def patched?(instance = nil)
13
+ (instance&.singleton_class || Net::HTTP).ancestors.include?(Instrumentation)
14
+ end
15
+
16
+ module Instrumentation
17
+ def connect
18
+ return super unless NetworkResiliency.enabled?(:http)
19
+
20
+ begin
21
+ ts = -NetworkResiliency.timestamp
22
+
23
+ super
24
+ rescue Net::OpenTimeout => e
25
+ # capture error
26
+ raise
27
+ ensure
28
+ ts += NetworkResiliency.timestamp
29
+
30
+ NetworkResiliency.record(
31
+ adapter: "http",
32
+ action: "connect",
33
+ destination: address,
34
+ error: e&.class,
35
+ duration: ts,
36
+ )
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -59,5 +59,5 @@ module NetworkResiliency
59
59
  end
60
60
  end
61
61
 
62
- # RedisClient.register(RedisAvenger)
63
- # Redis.new(middlewares: [RedisAvenger])
62
+ # RedisClient.register(NetworkResiliency::Adapter::Redis)
63
+ # Redis.new(middlewares: [NetworkResiliency::Adapter::Redis])
@@ -1,3 +1,3 @@
1
1
  module NetworkResiliency
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -1,123 +1,77 @@
1
- require "network_resiliency/stats"
2
1
  require "network_resiliency/version"
3
2
 
4
3
  module NetworkResiliency
5
- extend self
6
-
7
- def enabled?
8
- true
4
+ module Adapter
5
+ autoload :HTTP, "network_resiliency/adapter/http"
6
+ autoload :Faraday, "network_resiliency/adapter/faraday"
7
+ autoload :Redis, "network_resiliency/adapter/redis"
9
8
  end
10
9
 
11
- def sample?
12
- enabled? || rand < sample_rate
13
- end
14
-
15
- # def mode=(mode)
16
- # unless [ :avg, :x10, :sig1, :sig2, :sig3 ]
17
- # end
18
-
19
- def timeout(adapter, key)
20
- stats = self.stats(adapter, key)
10
+ extend self
21
11
 
22
- stats.avg * 10 if stats.n >= 100
23
- end
12
+ attr_accessor :statsd
24
13
 
25
- def stats(adapter, key)
26
- store.get(
27
- [
28
- adapter.class.to_s.split("::")[-1],
29
- key,
30
- ].join(":"),
31
- )
14
+ def configure
15
+ yield self
32
16
  end
33
17
 
34
- def record(adapter, key, milliseconds)
35
- compound_key = [
36
- adapter.class.to_s.split("::")[-1],
37
- key,
38
- ].join(":")
39
-
40
- # normalize timestamp
41
- milliseconds = [ milliseconds.round, 1 ].max
18
+ def enabled?(adapter)
19
+ return true if @enabled.nil?
42
20
 
43
- store.record(compound_key, milliseconds)
21
+ @enabled.is_a?(Proc) ? @enabled.call(adapter) : @enabled
44
22
  end
45
23
 
46
- def timestamp
47
- Process.clock_gettime(Process::CLOCK_MONOTONIC) * 1_000
48
- end
49
-
50
- def time
51
- # if block_given?
52
- ts = -timestamp
53
- yield
24
+ def enabled=(enabled)
25
+ unless [ true, false ].include?(enabled) || enabled.is_a?(Proc)
26
+ raise ArgumentError
27
+ end
54
28
 
55
- ts += timestamp
29
+ @enabled = enabled
56
30
  end
57
31
 
58
- def store
59
- @store ||= MemoryStore.new
60
- end
32
+ def enable!
33
+ original = @enabled
34
+ @enabled = true
61
35
 
62
- class Store
63
- def get(key)
64
- raise NotImplemented
65
- end
36
+ yield if block_given?
37
+ ensure
38
+ @enabled = original if block_given?
39
+ end
66
40
 
67
- def record(key, time)
68
- raise NotImplemented
69
- end
41
+ def disable!
42
+ original = @enabled
43
+ @enabled = false
70
44
 
71
- def flush
72
- raise NotImplemented
73
- end
45
+ yield if block_given?
46
+ ensure
47
+ @enabled = original if block_given?
74
48
  end
75
49
 
76
- class MemoryStore < Store
77
- def initialize(substore = nil)
78
- @substore = substore
79
- @data = {}
80
- end
50
+ def timestamp
51
+ # milliseconds
52
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) * 1_000
53
+ end
81
54
 
82
- def get(key)
83
- @data[key] ||= @substore&.get(key) || Stats.new
84
- end
55
+ # private
85
56
 
86
- def record(key, time)
87
- get(key) << time
88
- @substore&.record(key, time)
57
+ IP_ADDRESS_REGEX = Regexp.new(/\d{1,3}(\.\d{1,3}){3}/)
89
58
 
90
- self
91
- end
59
+ def record(adapter:, action:, destination:, duration:, error: nil)
60
+ # filter raw IP addresses
61
+ return if IP_ADDRESS_REGEX.match?(destination)
92
62
 
93
- def flush
94
- @substore&.flush
95
- end
63
+ NetworkResiliency.statsd&.distribution(
64
+ "network_resiliency.#{action}",
65
+ duration,
66
+ tags: {
67
+ adapter: adapter,
68
+ destination: destination,
69
+ error: error,
70
+ }.compact,
71
+ )
96
72
  end
97
73
 
98
- class RedisStore < Store
99
- def initialize(redis)
100
- @redis = redis
101
- end
102
-
103
- def cachekey(key)
104
- [ NetworkResiliency, key ].join(":")
105
- end
74
+ def reset
75
+ @enabled = nil
106
76
  end
107
77
  end
108
-
109
-
110
- require "network_resiliency/adapter/faraday"
111
- require "network_resiliency/adapter/redis"
112
-
113
- # ms granularity, round up, floor(1)
114
- #
115
-
116
- # storage
117
- # get(id) / record(id, time) / flush
118
-
119
- # local storage
120
- # - get(id) / save(id, time)
121
- # remote storage
122
- # - get(id) - sync
123
- # - save(id, time) - buffer and async flush
@@ -11,15 +11,16 @@ Gem::Specification.new do |s|
11
11
  s.summary = package.to_s
12
12
  s.version = package.const_get "VERSION"
13
13
 
14
- s.add_dependency "faraday"
14
+ s.required_ruby_version = ">= 3"
15
15
 
16
16
  s.add_development_dependency "byebug"
17
- s.add_development_dependency "codecov"
17
+ s.add_development_dependency "ddtrace", ">= 1"
18
+ s.add_development_dependency "dogstatsd-ruby", "<= 4.8.3"
19
+ s.add_development_dependency "faraday", "~> 1"
18
20
  s.add_development_dependency "faraday-rack"
19
21
  s.add_development_dependency "rack"
20
22
  s.add_development_dependency "rack-test"
21
- s.add_development_dependency "redis"
22
- s.add_development_dependency "redis-client", ">= 0.10"
23
+ s.add_development_dependency "redis", "~> 4"
23
24
  s.add_development_dependency "rspec"
24
25
  s.add_development_dependency "simplecov"
25
26
  end
metadata CHANGED
@@ -1,23 +1,23 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: network_resiliency
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.1
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-05-09 00:00:00.000000000 Z
11
+ date: 2023-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: faraday
14
+ name: byebug
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
- type: :runtime
20
+ type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
@@ -25,49 +25,49 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: byebug
28
+ name: ddtrace
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '1'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '1'
41
41
  - !ruby/object:Gem::Dependency
42
- name: codecov
42
+ name: dogstatsd-ruby
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "<="
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 4.8.3
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "<="
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 4.8.3
55
55
  - !ruby/object:Gem::Dependency
56
- name: faraday-rack
56
+ name: faraday
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '1'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: '1'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rack
70
+ name: faraday-rack
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rack-test
84
+ name: rack
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,7 +95,7 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: redis
98
+ name: rack-test
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -109,19 +109,19 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: redis-client
112
+ name: redis
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ">="
115
+ - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0.10'
117
+ version: '4'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ">="
122
+ - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '0.10'
124
+ version: '4'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rspec
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -163,6 +163,7 @@ files:
163
163
  - README.md
164
164
  - lib/network_resiliency.rb
165
165
  - lib/network_resiliency/adapter/faraday.rb
166
+ - lib/network_resiliency/adapter/http.rb
166
167
  - lib/network_resiliency/adapter/redis.rb
167
168
  - lib/network_resiliency/stats.rb
168
169
  - lib/network_resiliency/version.rb
@@ -179,7 +180,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
179
180
  requirements:
180
181
  - - ">="
181
182
  - !ruby/object:Gem::Version
182
- version: '0'
183
+ version: '3'
183
184
  required_rubygems_version: !ruby/object:Gem::Requirement
184
185
  requirements:
185
186
  - - ">="