This blog is part of our Ruby 2.6 series.
Before Ruby 2.6, if we created a large request with Net::HTTP, it would hang forever until request is interrupted. To fix this issue, write_timeout attribute and write_timeout= method is added to Net::HTTP in Ruby 2.6. Default value for write_timeout is 60 seconds and can be set to an integer or a float value.
Similarly, write_timeout attribute and write_timeout= method is added to Net::BufferedIO class.
If any chunk of response is not written within number of seconds provided to write_timeout, Net::WriteTimeout exception is raised. Net::WriteTimeout exception is not raised on Windows systems.
Example
1 2# server.rb 3 4require 'socket' 5 6server = TCPServer.new('localhost', 2345) 7loop do 8socket = server.accept 9end 10
Ruby 2.5.1
1 2# client.rb 3 4require 'net/http' 5 6connection = Net::HTTP.new('localhost', 2345) 7connection.open_timeout = 1 8connection.read_timeout = 3 9connection.start 10 11post = Net::HTTP::Post.new('/') 12body = (('a' _ 1023) + "\n") _ 5_000 13post.body = body 14 15puts "Sending #{body.bytesize} bytes" 16connection.request(post) 17
Output
1\$ RBENV_VERSION=2.5.1 ruby client.rb 2 3Sending 5120000 bytes
Ruby 2.5.1 processes request endlessly unless above program is interrupted.
Ruby 2.6.0-dev
Add write_timeout attribute to Net::HTTP instance in client.rb program.
1 2# client.rb 3 4require 'net/http' 5 6connection = Net::HTTP.new('localhost', 2345) 7connection.open_timeout = 1 8connection.read_timeout = 3 9 10# set write_timeout to 10 seconds 11 12connection.write_timeout = 10 13 14connection.start 15 16post = Net::HTTP::Post.new('/') 17body = (('a' _ 1023) + "\n") _ 5_000 18post.body = body 19 20puts "Sending #{body.bytesize} bytes" 21connection.request(post) 22
Output
1\$ RBENV_VERSION=2.6.0-dev ruby client.rb 2 3Sending 5120000 bytes 4Traceback (most recent call last): 513: `from client.rb:17:in `<main>`` 12: `from /net/http.rb:1479:in `request`` 611: `from /net/http.rb:1506:in `transport_request`` 10: `from /net/http.rb:1506:in `catch`` 79: `from /net/http.rb:1507:in `block in transport_request`` 8: `from /net/http/generic_request.rb:123:in `exec`` 87: `from /net/http/generic_request.rb:189:in `send_request_with_body`` 6: `from /net/protocol.rb:221:in `write`` 95: `from /net/protocol.rb:239:in `writing`` 4: `from /net/protocol.rb:222:in `block in write`` 103: `from /net/protocol.rb:249:in `write0`` 2: `from /net/protocol.rb:249:in `each_with_index`` 111: `from /net/protocol.rb:249:in `each`` `/net/protocol.rb:270:in `block in write0`: Net::WriteTimeout (Net::WriteTimeout)` 12
In Ruby 2.6.0, above program is terminated raising Net::WriteTimeout exception after 10 seconds (value set to write_timeout attribute).
Here is relevant commit and discussion for this change.