Class: HTTP::Timeout::Global
- Defined in:
- lib/http/timeout/global.rb,
sig/http.rbs
Overview
Timeout handler with a single global timeout for the entire request
Constant Summary collapse
- WAIT_RESULTS =
I/O wait result symbols returned by non-blocking operations
%i[wait_readable wait_writable].freeze
Constants inherited from Null
Instance Attribute Summary
Attributes inherited from Null
Instance Method Summary collapse
-
#connect(socket_class, host, port, nodelay: false) ⇒ void
Connects to a socket with global timeout.
-
#connect_ssl ⇒ void
Starts an SSL connection on a socket.
-
#effective_timeout(per_op_timeout) ⇒ Numeric
private
Computes the effective timeout as the minimum of global and per-operation.
-
#handle_io_result(result) ⇒ Object, Symbol
private
Handles the result of an I/O operation.
-
#initialize(global_timeout:, read_timeout: nil, write_timeout: nil, connect_timeout: nil) ⇒ HTTP::Timeout::Global
constructor
Initializes global timeout with options.
-
#log_time ⇒ void
private
Logs elapsed time and checks for timeout.
-
#perform_io(per_op_timeout = nil) { ... } ⇒ Object
private
Performs I/O operation with timeout tracking.
-
#read_nonblock(size, buffer = nil) ⇒ String, Symbol
private
Reads from socket in non-blocking mode.
-
#readpartial(size, buffer = nil) ⇒ String, :eof
Read from the socket.
-
#reset_counter ⇒ Numeric
Resets the time left counter to initial timeout.
-
#reset_timer ⇒ Time
private
Resets the I/O timer to current time.
-
#wait_for_io(result, per_op_timeout = nil) ⇒ void
private
Waits for an I/O readiness based on the result type.
-
#wait_readable_or_timeout(per_op = nil) ⇒ void
private
Waits for a socket to become readable.
-
#wait_writable_or_timeout(per_op = nil) ⇒ void
private
Waits for a socket to become writable.
-
#write(data) ⇒ Integer, :eof
(also: #<<)
Write to the socket.
-
#write_nonblock(data) ⇒ Integer, Symbol
private
Writes to socket in non-blocking mode.
Methods inherited from Null
#close, #closed?, #native_timeout?, #open_socket, #open_with_timeout, #read_timeout, #rescue_readable, #rescue_writable, #start_tls, #write_timeout
Constructor Details
#initialize(global_timeout:, read_timeout: nil, write_timeout: nil, connect_timeout: nil) ⇒ HTTP::Timeout::Global
Initializes global timeout with options
25 26 27 28 29 30 31 32 |
# File 'lib/http/timeout/global.rb', line 25 def initialize(global_timeout:, read_timeout: nil, write_timeout: nil, connect_timeout: nil) super @timeout = @time_left = global_timeout @read_timeout = read_timeout @write_timeout = write_timeout @connect_timeout = connect_timeout end |
Instance Method Details
#connect(socket_class, host, port, nodelay: false) ⇒ void
This method returns an undefined value.
Connects to a socket with global timeout
56 57 58 59 60 61 62 |
# File 'lib/http/timeout/global.rb', line 56 def connect(socket_class, host, port, nodelay: false) reset_timer @socket = open_socket(socket_class, host, port, connect_timeout: effective_timeout(@connect_timeout)) @socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay log_time end |
#connect_ssl ⇒ void
This method returns an undefined value.
Starts an SSL connection on a socket
71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/http/timeout/global.rb', line 71 def connect_ssl reset_timer begin @socket.connect_nonblock rescue IO::WaitReadable wait_readable_or_timeout(@connect_timeout) retry rescue IO::WaitWritable wait_writable_or_timeout(@connect_timeout) retry end end |
#effective_timeout(per_op_timeout) ⇒ Numeric
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Computes the effective timeout as the minimum of global and per-operation
203 204 205 206 207 |
# File 'lib/http/timeout/global.rb', line 203 def effective_timeout(per_op_timeout) return @time_left unless per_op_timeout [per_op_timeout, @time_left].min end |
#handle_io_result(result) ⇒ Object, Symbol
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Handles the result of an I/O operation
154 155 156 |
# File 'lib/http/timeout/global.rb', line 154 def handle_io_result(result) result.nil? ? :eof : result end |
#log_time ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Logs elapsed time and checks for timeout
221 222 223 224 225 226 |
# File 'lib/http/timeout/global.rb', line 221 def log_time @time_left -= (Time.now - @started) raise TimeoutError, "Timed out after using the allocated #{@timeout} seconds" if @time_left <= 0 reset_timer end |
#perform_io(per_op_timeout = nil) { ... } ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Performs I/O operation with timeout tracking
135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/http/timeout/global.rb', line 135 def perform_io(per_op_timeout = nil) reset_timer loop do result = yield return handle_io_result(result) unless WAIT_RESULTS.include?(result) wait_for_io(result, per_op_timeout) rescue IO::WaitReadable then wait_readable_or_timeout(per_op_timeout) rescue IO::WaitWritable then wait_writable_or_timeout(per_op_timeout) end rescue EOFError :eof end |
#read_nonblock(size, buffer = nil) ⇒ String, Symbol
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Reads from socket in non-blocking mode
118 119 120 |
# File 'lib/http/timeout/global.rb', line 118 def read_nonblock(size, buffer = nil) @socket.read_nonblock(size, buffer, exception: false) end |
#readpartial(size, buffer = nil) ⇒ String, :eof
Read from the socket
94 95 96 |
# File 'lib/http/timeout/global.rb', line 94 def readpartial(size, buffer = nil) perform_io(@read_timeout) { read_nonblock(size, buffer) } end |
#reset_counter ⇒ Numeric
Resets the time left counter to initial timeout
41 42 43 |
# File 'lib/http/timeout/global.rb', line 41 def reset_counter @time_left = @timeout end |
#reset_timer ⇒ Time
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Resets the I/O timer to current time
213 214 215 |
# File 'lib/http/timeout/global.rb', line 213 def reset_timer @started = Time.now end |
#wait_for_io(result, per_op_timeout = nil) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Waits for an I/O readiness based on the result type
164 165 166 167 168 169 170 |
# File 'lib/http/timeout/global.rb', line 164 def wait_for_io(result, per_op_timeout = nil) if result == :wait_readable wait_readable_or_timeout(per_op_timeout) else wait_writable_or_timeout(per_op_timeout) end end |
#wait_readable_or_timeout(per_op = nil) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Waits for a socket to become readable
177 178 179 180 181 182 183 |
# File 'lib/http/timeout/global.rb', line 177 def wait_readable_or_timeout(per_op = nil) timeout = effective_timeout(per_op) result = @socket.to_io.wait_readable(timeout) log_time raise TimeoutError, "Read timed out after #{per_op} seconds" if per_op && result.nil? end |
#wait_writable_or_timeout(per_op = nil) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Waits for a socket to become writable
190 191 192 193 194 195 196 |
# File 'lib/http/timeout/global.rb', line 190 def wait_writable_or_timeout(per_op = nil) timeout = effective_timeout(per_op) result = @socket.to_io.wait_writable(timeout) log_time raise TimeoutError, "Write timed out after #{per_op} seconds" if per_op && result.nil? end |
#write(data) ⇒ Integer, :eof Also known as: <<
Write to the socket
106 107 108 |
# File 'lib/http/timeout/global.rb', line 106 def write(data) perform_io(@write_timeout) { write_nonblock(data) } end |
#write_nonblock(data) ⇒ Integer, Symbol
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Writes to socket in non-blocking mode
126 127 128 |
# File 'lib/http/timeout/global.rb', line 126 def write_nonblock(data) @socket.write_nonblock(data, exception: false) end |