client-api-builder 0.8.0 → 0.10.0

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.
@@ -6,6 +6,9 @@ require 'json'
6
6
 
7
7
  module ClientApiBuilder
8
8
  module Router
9
+ # Status codes accepted when a route lists no expected_response_codes
10
+ SUCCESS_CODE = /\A2\d\d\z/
11
+
9
12
  def self.included(base)
10
13
  base.extend InheritanceHelper::Methods
11
14
  base.extend ClassMethods
@@ -60,7 +63,10 @@ module ClientApiBuilder
60
63
  query_params: {},
61
64
  response_procs: {},
62
65
  max_retries: 1,
63
- sleep: 0.05
66
+ sleep: 0.05,
67
+ backoff: 1,
68
+ max_sleep: nil,
69
+ jitter: false
64
70
  }.freeze
65
71
  end
66
72
 
@@ -127,14 +133,27 @@ module ClientApiBuilder
127
133
  add_value_to_class_method(:default_options, connection_options: connection_options)
128
134
  end
129
135
 
130
- def configure_retries(max_retries, sleep_time_between_retries_in_seconds = 0.05)
136
+ # max_retries is the total number of attempts. The sleep before retry n is
137
+ # sleep * backoff**(n - 1), capped at max_sleep when given. jitter randomly
138
+ # shortens each sleep: true by up to all of it, a number (0..1) by up to that fraction.
139
+ def configure_retries(max_retries, sleep_time_between_retries_in_seconds = 0.05,
140
+ backoff: 1, max_sleep: nil, jitter: false)
131
141
  add_value_to_class_method(
132
142
  :default_options,
133
143
  max_retries: max_retries,
134
- sleep: sleep_time_between_retries_in_seconds
144
+ sleep: sleep_time_between_retries_in_seconds,
145
+ backoff: backoff,
146
+ max_sleep: max_sleep,
147
+ jitter: jitter
135
148
  )
136
149
  end
137
150
 
151
+ # configure_retries with a sleep that starts at initial and doubles (by default)
152
+ # after each failed attempt, never exceeding max
153
+ def configure_exponential_retries(attempts:, initial: 0.1, max: 10, multiplier: 2, jitter: false)
154
+ configure_retries(attempts, initial, backoff: multiplier, max_sleep: max, jitter: jitter)
155
+ end
156
+
138
157
  # add a query param to all requests
139
158
  def query_param(name, value = nil, &block)
140
159
  query_params = deep_dup_hash(default_options[:query_params])
@@ -562,8 +581,10 @@ module ClientApiBuilder
562
581
  url
563
582
  end
564
583
 
584
+ # Checks the status code rather than the response class, so any response object with a
585
+ # Net::HTTPResponse-style string code works (e.g. from a non-Net::HTTP transport)
565
586
  def expected_response_code!(response, expected_response_codes, _options)
566
- return if expected_response_codes.empty? && response.is_a?(Net::HTTPSuccess)
587
+ return if expected_response_codes.empty? && SUCCESS_CODE.match?(response.code.to_s)
567
588
  return if expected_response_codes.include?(response.code)
568
589
 
569
590
  raise(::ClientApiBuilder::UnexpectedResponse.new("unexpected response code #{response.code}", response))
@@ -635,7 +656,20 @@ module ClientApiBuilder
635
656
  end
636
657
 
637
658
  def get_retry_request_sleep_time(_exception, options)
638
- options[:sleep] || self.class.default_options[:sleep] || 0.05
659
+ sleep_time = options[:sleep] || self.class.default_options[:sleep] || 0.05
660
+ backoff = options[:backoff] || self.class.default_options[:backoff] || 1
661
+ sleep_time *= backoff**(@request_attempts - 1)
662
+ max_sleep = options[:max_sleep] || self.class.default_options[:max_sleep]
663
+ sleep_time = [sleep_time, max_sleep].min if max_sleep
664
+ apply_retry_jitter(sleep_time, options.fetch(:jitter) { self.class.default_options[:jitter] })
665
+ end
666
+
667
+ # shortens sleep_time by a random amount: up to all of it for true, up to that fraction for a number
668
+ def apply_retry_jitter(sleep_time, jitter)
669
+ return sleep_time unless jitter
670
+
671
+ jitter = 1 if jitter == true
672
+ sleep_time * (1 - (jitter * rand))
639
673
  end
640
674
 
641
675
  def get_retry_request_max_retries(options)
@@ -657,7 +691,7 @@ module ClientApiBuilder
657
691
  def retry_request?(exception, _options)
658
692
  case exception
659
693
  when Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNRESET,
660
- Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketError, EOFError
694
+ Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketError, EOFError, ::ClientApiBuilder::RetryableError
661
695
  true
662
696
  else
663
697
  false
@@ -10,6 +10,11 @@ module ClientApiBuilder
10
10
  module ClassMethods
11
11
  SECTION_NAME = /\A[a-z_][a-z0-9_]*\z/i
12
12
 
13
+ # Section router classes by name, including inherited sections
14
+ def section_routers
15
+ {}.freeze
16
+ end
17
+
13
18
  # Defines <name>_router (the section's NestedRouter class) and <name> (its router for a
14
19
  # client instance) with closures, so anonymous client classes and any option values work.
15
20
  # inherit: opts the section into root client settings (see NestedRouter.inherit_from_root);
@@ -31,6 +36,7 @@ module ClientApiBuilder
31
36
  kls.class_eval(&block) if block
32
37
 
33
38
  define_singleton_method(:"#{name}_router") { kls }
39
+ add_value_to_class_method(:section_routers, name.to_sym => kls)
34
40
  define_section_accessor(name, nested_router_options)
35
41
  end
36
42
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  module ClientApiBuilder
4
4
  # Gem version, bumped by release-please
5
- VERSION = '0.8.0'
5
+ VERSION = '0.10.0'
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: client-api-builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Doug Youch
@@ -40,6 +40,19 @@ files:
40
40
  - lib/client-api-builder.rb
41
41
  - lib/client_api_builder/active_support_log_subscriber.rb
42
42
  - lib/client_api_builder/active_support_notifications.rb
43
+ - lib/client_api_builder/connection_pools.rb
44
+ - lib/client_api_builder/connection_pools/connection.rb
45
+ - lib/client_api_builder/connection_pools/pool.rb
46
+ - lib/client_api_builder/connection_pools/pool_set.rb
47
+ - lib/client_api_builder/connection_pools/settings.rb
48
+ - lib/client_api_builder/http2.rb
49
+ - lib/client_api_builder/http2/connection.rb
50
+ - lib/client_api_builder/http2/connection_set.rb
51
+ - lib/client_api_builder/http2/exchange.rb
52
+ - lib/client_api_builder/http2/request_headers.rb
53
+ - lib/client_api_builder/http2/response_body.rb
54
+ - lib/client_api_builder/http2/response_builder.rb
55
+ - lib/client_api_builder/http2/tls_socket.rb
43
56
  - lib/client_api_builder/nested_router.rb
44
57
  - lib/client_api_builder/net_http_request.rb
45
58
  - lib/client_api_builder/query_params.rb