nonnative 3.38.0 → 3.40.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d53bdf381bf4cb897538cc4520e499b0116e8fc31566930ae1612859dda4d6a
4
- data.tar.gz: 809f8545b4fe5e6d49289840572247148c38f2a0cd3647919b5b77f473b88b5e
3
+ metadata.gz: f3513aa619cd9dab8134d9c4e8d22d333dcd2300f92e271cb8dee10ed7c0de2c
4
+ data.tar.gz: 4aeae3fd49ad6bd1da6b929bfa666c17c3c346a73a56b430ca7214a82ee19698
5
5
  SHA512:
6
- metadata.gz: 34adbd873e0eedd1b994aff7afe5ebc33834ab3f820dcbd2b551d619c851b083ae897828c88ad6c5b185b3d174390364aca1fdd9be85440fc2a5175e574eb686
7
- data.tar.gz: 06ea5ded95fd98a9ba589cf5b5a8a8d567e07e295fbe72445332997ccb21b1649aa8edb0fe21054a17b91c527e023aa4e44c0724ce66ca0e43c4f39c3f7c4a69
6
+ metadata.gz: d5c02d41c403e663ba1ffe2e8f36e67fe4a2a36910b60a921d0e02c3ac84b1c68be01158ff223c40ee3e6990e429d79faf79eada9e538195a26652523d89813a
7
+ data.tar.gz: 6be1f9067df0fd1c121d0604813d3f91b4e9bbe9cbecfcd10aacd8a96a06a76f27a0a42bb3a08398cb7f0c3e68678a42c0f55b62390f304461814332a1e7e1bf
data/README.md CHANGED
@@ -182,8 +182,9 @@ expect(response.code).to eq(200)
182
182
  ```
183
183
 
184
184
  HTTP error statuses are returned as response objects so callers can inspect `.code` and `.body`.
185
- Request timeouts and broken connections raise their RestClient exceptions; observability requests are
186
- not retried automatically.
185
+ Broken connections raise their RestClient exceptions, and a request timeout raises either a RestClient
186
+ timeout exception or `Timeout::Error` (the latter when `read_timeout` bounds a Net::HTTP retry of an
187
+ idempotent verb); observability requests are not retried automatically.
187
188
 
188
189
  `Nonnative.grpc_health` is a helper for the standard gRPC health checking protocol:
189
190
 
@@ -608,8 +609,10 @@ end
608
609
  The system allows you to define an in-process HTTP forward proxy server for external systems, e.g. `api.github.com`. This is a server implementation, not a fault-injection service proxy.
609
610
 
610
611
  The upstream scheme defaults to HTTPS on the scheme's default port; pass `scheme:`/`port:` to
611
- `Nonnative::HTTPProxyServer.new` to target an `http://` upstream or a non-default port. The proxy
612
- forwards the request path and query for `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE`, and
612
+ `Nonnative::HTTPProxyServer.new` to target an `http://` upstream or a non-default port. The whole
613
+ upstream call defaults to a one-second bound, including Net::HTTP's built-in retry of an
614
+ unresponsive idempotent request; pass `upstream_timeout:` to tune it for a slow dependency. The
615
+ proxy forwards the request path and query for `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE`, and
613
616
  `OPTIONS`, while removing proxy credentials, `Host`, `Accept-Encoding`, hop-by-hop headers, and
614
617
  headers nominated by `Connection` before the upstream request.
615
618
 
@@ -93,6 +93,8 @@ module Nonnative
93
93
  process = Nonnative::ConfigurationProcess.new
94
94
  yield process
95
95
 
96
+ raise ArgumentError, "Process '#{process.name}' requires 'command' or 'go'" if process.command.nil?
97
+
96
98
  processes << process
97
99
  end
98
100
 
@@ -157,7 +159,7 @@ module Nonnative
157
159
  tools = go.tools || []
158
160
 
159
161
  -> { Nonnative.go_argv(tools, go.output, go.executable, go.command, *params) }
160
- else
162
+ elsif process.command
161
163
  -> { process.command }
162
164
  end
163
165
  end
@@ -18,7 +18,8 @@ module Nonnative
18
18
  @host = host
19
19
  @exceptions = [
20
20
  RestClient::Exceptions::Timeout,
21
- RestClient::ServerBrokeConnection
21
+ RestClient::ServerBrokeConnection,
22
+ ::Timeout::Error
22
23
  ]
23
24
  end
24
25
 
@@ -40,7 +41,7 @@ module Nonnative
40
41
  # @param opts [Hash] RestClient request options (e.g. `headers`, `read_timeout`, `open_timeout`)
41
42
  # @return [RestClient::Response, String] response for non-2xx errors, otherwise the RestClient result
42
43
  def get(pathname, opts = {})
43
- with_exception do
44
+ with_exception(opts) do
44
45
  resource(pathname, opts).get
45
46
  end
46
47
  end
@@ -52,7 +53,7 @@ module Nonnative
52
53
  # @param opts [Hash] RestClient request options
53
54
  # @return [RestClient::Response, String] response for non-2xx errors, otherwise the RestClient result
54
55
  def post(pathname, payload, opts = {})
55
- with_exception do
56
+ with_exception(opts) do
56
57
  resource(pathname, opts).post(payload)
57
58
  end
58
59
  end
@@ -63,7 +64,7 @@ module Nonnative
63
64
  # @param opts [Hash] RestClient request options
64
65
  # @return [RestClient::Response, String] response for non-2xx errors, otherwise the RestClient result
65
66
  def delete(pathname, opts = {})
66
- with_exception do
67
+ with_exception(opts) do
67
68
  resource(pathname, opts).delete
68
69
  end
69
70
  end
@@ -75,7 +76,7 @@ module Nonnative
75
76
  # @param opts [Hash] RestClient request options
76
77
  # @return [RestClient::Response, String] response for non-2xx errors, otherwise the RestClient result
77
78
  def put(pathname, payload, opts = {})
78
- with_exception do
79
+ with_exception(opts) do
79
80
  resource(pathname, opts).put(payload)
80
81
  end
81
82
  end
@@ -87,7 +88,7 @@ module Nonnative
87
88
  # @param opts [Hash] RestClient request options
88
89
  # @return [RestClient::Response, String] response for non-2xx errors, otherwise the RestClient result
89
90
  def patch(pathname, payload, opts = {})
90
- with_exception do
91
+ with_exception(opts) do
91
92
  resource(pathname, opts).patch(payload)
92
93
  end
93
94
  end
@@ -98,7 +99,7 @@ module Nonnative
98
99
  # @param opts [Hash] RestClient request options (e.g. `headers`, `read_timeout`, `open_timeout`)
99
100
  # @return [RestClient::Response, String] response for non-2xx errors, otherwise the RestClient result
100
101
  def head(pathname, opts = {})
101
- with_exception do
102
+ with_exception(opts) do
102
103
  resource(pathname, opts).head
103
104
  end
104
105
  end
@@ -109,7 +110,7 @@ module Nonnative
109
110
  # @param opts [Hash] RestClient request options (e.g. `headers`, `read_timeout`, `open_timeout`)
110
111
  # @return [RestClient::Response, String] response for non-2xx errors, otherwise the RestClient result
111
112
  def options(pathname, opts = {})
112
- with_exception do
113
+ with_exception(opts) do
113
114
  RestClient::Request.execute(opts.merge(method: :options, url: request_url(pathname)))
114
115
  end
115
116
  end
@@ -131,8 +132,12 @@ module Nonnative
131
132
  URI.join(host, pathname).to_s
132
133
  end
133
134
 
134
- def with_exception
135
- yield
135
+ # Net::HTTP silently retries idempotent verbs once on a read timeout, so bound the whole call
136
+ # (including any retry) by the wall clock rather than trusting `:read_timeout` alone.
137
+ def with_exception(opts = {}, &)
138
+ timeout = opts[:read_timeout]
139
+
140
+ timeout ? ::Timeout.timeout(timeout, &) : yield
136
141
  rescue *exceptions => e
137
142
  raise e
138
143
  rescue RestClient::Exception => e
@@ -59,7 +59,8 @@ module Nonnative
59
59
  ].freeze
60
60
 
61
61
  GATEWAY_TIMEOUT_ERRORS = [
62
- RestClient::Exceptions::Timeout
62
+ RestClient::Exceptions::Timeout,
63
+ ::Timeout::Error
63
64
  ].freeze
64
65
 
65
66
  GATEWAY_CONNECTION_ERRORS = [
@@ -112,10 +113,12 @@ module Nonnative
112
113
  # @return [RestClient::Response] response for error statuses, otherwise RestClient return value
113
114
  # @raise [Sinatra::Halt] with a gateway status when the upstream is unavailable or times out
114
115
  def api_response(method:, url:, headers:, payload: nil)
115
- options = { method:, url:, headers: }
116
+ options = { method:, url:, headers:, open_timeout: settings.upstream_timeout, read_timeout: settings.upstream_timeout }
116
117
  options[:payload] = payload unless payload.nil?
117
118
 
118
- RestClient::Request.execute(options)
119
+ # Net::HTTP retries idempotent verbs once on a read timeout, so bound the whole
120
+ # call (including any retry) by the wall clock rather than trusting read_timeout alone.
121
+ ::Timeout.timeout(settings.upstream_timeout) { RestClient::Request.execute(options) }
119
122
  rescue *GATEWAY_TIMEOUT_ERRORS
120
123
  halt 504
121
124
  rescue *GATEWAY_CONNECTION_ERRORS
@@ -246,11 +249,13 @@ module Nonnative
246
249
  # @param service [Nonnative::ConfigurationServer] server configuration
247
250
  # @param scheme [String] upstream scheme, `"http"` or `"https"`
248
251
  # @param port [Integer, nil] upstream port; `nil` uses the scheme's default port
249
- def initialize(host, service, scheme: 'https', port: nil)
252
+ # @param upstream_timeout [Numeric] maximum seconds for each upstream operation (defaults to `1.0`)
253
+ def initialize(host, service, scheme: 'https', port: nil, upstream_timeout: ConfigurationRunner::DEFAULT_TIMEOUT)
250
254
  http_service = Class.new(Nonnative::HTTPProxy) do
251
255
  set :host, host
252
256
  set :scheme, scheme
253
257
  set :port, port
258
+ set :upstream_timeout, upstream_timeout
254
259
  end
255
260
 
256
261
  super(http_service.new, service)
@@ -14,8 +14,9 @@ module Nonnative
14
14
  #
15
15
  # Requests are performed using {Nonnative::HTTPClient}, so callers may pass RestClient options
16
16
  # such as `headers`, `open_timeout`, and `read_timeout`. HTTP error statuses are returned as response
17
- # objects; timeouts and broken connections raise their RestClient exceptions. Requests are not
18
- # retried automatically.
17
+ # objects; broken connections raise their RestClient exceptions, and a timeout raises either a
18
+ # RestClient timeout exception or `Timeout::Error` (the latter when `read_timeout` bounds a Net::HTTP
19
+ # retry of an idempotent verb). Requests are not retried automatically.
19
20
  #
20
21
  # @example
21
22
  # Nonnative.configure do |config|
@@ -4,5 +4,5 @@ module Nonnative
4
4
  # The current gem version.
5
5
  #
6
6
  # @return [String]
7
- VERSION = '3.38.0'
7
+ VERSION = '3.40.0'
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nonnative
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.38.0
4
+ version: 3.40.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alejandro Falkowski