network_resiliency 0.0.2 → 0.1.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: 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
  - - ">="