excon 0.103.0 → 0.105.0

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: 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