excon 0.103.0 → 0.105.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: 2c1759dde8542ab4e6147d2c51ce7e674d4fdd46b48f0aed3a77ed823917d336
4
- data.tar.gz: 5c4c66737d283ed9d4d186cd46809c5c2fd0fc346c06564140b39a131fdfb44f
3
+ metadata.gz: bf1521a5cb2831330da53ba05456633a8219047e6a0d0f7892b32c8d49a074c0
4
+ data.tar.gz: 242837bbe9feba5985fc5fbe969a8d22cc9ab36bc4bd80479377d1a9596e2d05
5
5
  SHA512:
6
- metadata.gz: 803189e9d2dc991e48114c4f5ec7071ff04e4ea3f88d6872b3bcfe066cda38055c98b44cad83e5b9edabb677684b75c1a673c232303826a87857ba214c75cf6b
7
- data.tar.gz: cab31317bdbc12398a33ce0b4a385584ca5c3e1cd2be2b201fb5e7ac0161b330e235d0ecd489fa304356367ab98fc868cc610d3afaf12bd3b4636ea182cda92e
6
+ metadata.gz: ba2f9e23944c16efbbc8edb7515af65629b1d763b7e20bea60180d4c8e995ec3829b3152c48308f760c2ac79e39851de069046b614bc6c725f3e2210f4d9d77f
7
+ data.tar.gz: e399f1c89cf8fa3eb1f03f2ff8430272d0db3ebc95c9d9cd23362cd46c0b6d7a4515ffd181aaf8d51fa3b0218915bc762e42090c8c5048d7f9750d23cf21039b
data/README.md CHANGED
@@ -179,6 +179,10 @@ connection.request(:read_timeout => 360)
179
179
  # set longer write_timeout (default is 60 seconds)
180
180
  connection.request(:write_timeout => 360)
181
181
 
182
+ # set a request timeout in seconds (default is no timeout).
183
+ # the timeout may be an integer or a float to support sub-second granularity (e.g., 1, 60, 0.005 and 3.5).
184
+ connection.request(:timeout => 0.1) # timeout if the entire request takes longer than 100 milliseconds
185
+
182
186
  # Enable the socket option TCP_NODELAY on the underlying socket.
183
187
  #
184
188
  # This can improve response time when sending frequent short
@@ -192,10 +196,20 @@ connection = Excon.new('http://geemus.com/', :connect_timeout => 360)
192
196
  # opt-out of nonblocking operations for performance and/or as a workaround
193
197
  connection = Excon.new('http://geemus.com/', :nonblock => false)
194
198
 
199
+ # DEPRECATED in favour of `resolv_resolver` (see below)
195
200
  # set up desired dns_timeouts for resolving addresses (default is set by Resolv)
196
201
  # it accepts an integer or an array of integers for retrying with different timeouts
197
202
  # see Resolv::DNS#timeouts for more details (https://ruby-doc.org/3.2.2/stdlibs/resolv/Resolv/DNS.html#method-i-timeouts-3D)
198
203
  connection = Excon.new('http://geemus.com/', :dns_timeouts => 3)
204
+
205
+ # set a custom resolver for Resolv
206
+ # you can use custom nameservers and timeouts
207
+ # `timeouts` accepts an integer or an array of integers for retrying with different timeouts
208
+ # see Resolv::DNS#timeouts for more details (https://ruby-doc.org/3.2.2/stdlibs/resolv/Resolv/DNS.html#method-i-timeouts-3D)
209
+ dns_resolver = Resolv::DNS.new(nameserver: ['127.0.0.1'])
210
+ dns_resolver.timeouts = 3
211
+ resolver = Resolv.new([Resolv::Hosts.new, dns_resolver])
212
+ connection = Excon.new('http://geemus.com', :resolv_resolver => resolver)
199
213
  ```
200
214
 
201
215
  ## Chunked Requests
@@ -230,6 +230,13 @@ module Excon
230
230
  def request(params={}, &block)
231
231
  # @data has defaults, merge in new params to override
232
232
  datum = @data.merge(params)
233
+
234
+ # Set the deadline for the current request in order to determine when we have run out of time.
235
+ # Only set when a request timeout has been defined.
236
+ if datum[:timeout]
237
+ datum[:deadline] = Process.clock_gettime(Process::CLOCK_MONOTONIC) + datum[:timeout]
238
+ end
239
+
233
240
  datum[:headers] = @data[:headers].merge(datum[:headers] || {})
234
241
 
235
242
  validate_params(:request, params, datum[:middlewares])
@@ -59,8 +59,10 @@ module Excon
59
59
  :query,
60
60
  :read_timeout,
61
61
  :request_block,
62
+ :resolv_resolver,
62
63
  :response_block,
63
64
  :stubs,
65
+ :timeout,
64
66
  :user,
65
67
  :versions,
66
68
  :write_timeout
@@ -162,6 +164,7 @@ module Excon
162
164
  :omit_default_port => false,
163
165
  :persistent => false,
164
166
  :read_timeout => 60,
167
+ :resolv_resolver => nil,
165
168
  :retry_errors => DEFAULT_RETRY_ERRORS,
166
169
  :retry_limit => DEFAULT_RETRY_LIMIT,
167
170
  :ssl_verify_peer => true,
@@ -169,6 +172,7 @@ module Excon
169
172
  :stubs => :global,
170
173
  :tcp_nodelay => false,
171
174
  :thread_safe_sockets => true,
175
+ :timeout => nil,
172
176
  :uri_parser => URI,
173
177
  :versions => VERSIONS,
174
178
  :write_timeout => 60
data/lib/excon/socket.rb CHANGED
@@ -25,6 +25,13 @@ module Excon
25
25
  else # Ruby <= 2.0
26
26
  [Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable]
27
27
  end
28
+ # Maps a socket operation to a timeout property.
29
+ OPERATION_TO_TIMEOUT = {
30
+ :connect_read => :connect_timeout,
31
+ :connect_write => :connect_timeout,
32
+ :read => :read_timeout,
33
+ :write => :write_timeout
34
+ }.freeze
28
35
 
29
36
  def params
30
37
  Excon.display_warning('Excon::Socket#params is deprecated use Excon::Socket#data instead.')
@@ -121,9 +128,16 @@ module Excon
121
128
  family = @data[:proxy][:family]
122
129
  end
123
130
 
124
- dns_resolver = Resolv::DNS.new
125
- dns_resolver.timeouts = @data[:dns_timeouts]
126
- resolver = Resolv.new([Resolv::Hosts.new, dns_resolver])
131
+ resolver = @data[:resolv_resolver] || Resolv.new
132
+
133
+ # Deprecated
134
+ if @data[:dns_timeouts]
135
+ Excon.display_warning('dns_timeouts is deprecated, use resolv_resolver instead.')
136
+ dns_resolver = Resolv::DNS.new
137
+ dns_resolver.timeouts = @data[:dns_timeouts]
138
+ resolver = Resolv.new([Resolv::Hosts.new, dns_resolver])
139
+ end
140
+
127
141
  resolver.each_address(hostname) do |ip|
128
142
  # already succeeded on previous addrinfo
129
143
  if @socket
@@ -297,17 +311,33 @@ module Excon
297
311
  end
298
312
 
299
313
  def select_with_timeout(socket, type)
314
+ timeout_kind = type
315
+ timeout = @data[OPERATION_TO_TIMEOUT[type]]
316
+
317
+ # Check whether the request has a timeout configured.
318
+ if @data.include?(:deadline)
319
+ request_timeout = request_time_remaining
320
+
321
+ # If the time remaining until the request times out is less than the timeout for the type of select,
322
+ # use the time remaining as the timeout instead.
323
+ if request_timeout < timeout
324
+ timeout_kind = :request
325
+ timeout = request_timeout
326
+ end
327
+ end
328
+
300
329
  select = case type
301
330
  when :connect_read
302
- IO.select([socket], nil, nil, @data[:connect_timeout])
331
+ IO.select([socket], nil, nil, timeout)
303
332
  when :connect_write
304
- IO.select(nil, [socket], nil, @data[:connect_timeout])
333
+ IO.select(nil, [socket], nil, timeout)
305
334
  when :read
306
- IO.select([socket], nil, nil, @data[:read_timeout])
335
+ IO.select([socket], nil, nil, timeout)
307
336
  when :write
308
- IO.select(nil, [socket], nil, @data[:write_timeout])
337
+ IO.select(nil, [socket], nil, timeout)
309
338
  end
310
- select || raise(Excon::Errors::Timeout.new("#{type} timeout reached"))
339
+
340
+ select || raise(Excon::Errors::Timeout.new("#{timeout_kind} timeout reached"))
311
341
  end
312
342
 
313
343
  def unpacked_sockaddr
@@ -317,5 +347,16 @@ module Excon
317
347
  raise
318
348
  end
319
349
  end
350
+
351
+ # Returns the remaining time in seconds until we reach the deadline for the request timeout.
352
+ # Raises an exception if we have exceeded the request timeout's deadline.
353
+ def request_time_remaining
354
+ now = Process.clock_gettime(Process::CLOCK_MONOTONIC)
355
+ deadline = @data[:deadline]
356
+
357
+ raise(Excon::Errors::Timeout.new('request timeout reached')) if now >= deadline
358
+
359
+ deadline - now
360
+ end
320
361
  end
321
362
  end
data/lib/excon/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Excon
4
- VERSION = '0.103.0'
4
+ VERSION = '0.105.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: excon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.103.0
4
+ version: 0.105.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - dpiddy (Dan Peterson)
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-09-13 00:00:00.000000000 Z
13
+ date: 2023-11-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec