This blog is part of our Ruby 2.6 series. Ruby 2.6.0-preview2 was recently released.

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
# server.rb

require 'socket'

server = TCPServer.new('localhost', 2345)
loop do
  socket = server.accept
end
Ruby 2.5.1
# client.rb

require 'net/http'

connection = Net::HTTP.new('localhost', 2345)
connection.open_timeout = 1
connection.read_timeout = 3
connection.start

post = Net::HTTP::Post.new('/')
body = (('a' * 1023) + "\n") * 5_000
post.body = body

puts "Sending #{body.bytesize} bytes"
connection.request(post)
Output
$ RBENV_VERSION=2.5.1 ruby client.rb

Sending 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.

# client.rb

require 'net/http'

connection = Net::HTTP.new('localhost', 2345)
connection.open_timeout = 1
connection.read_timeout = 3

# set write_timeout to 10 seconds
connection.write_timeout = 10

connection.start

post = Net::HTTP::Post.new('/')
body = (('a' * 1023) + "\n") * 5_000
post.body = body

puts "Sending #{body.bytesize} bytes"
connection.request(post)
Output
$ RBENV_VERSION=2.6.0-dev ruby client.rb

Sending 5120000 bytes
Traceback (most recent call last):
    13: `from client.rb:17:in `<main>``
    12: `from /net/http.rb:1479:in `request``
    11: `from /net/http.rb:1506:in `transport_request``
    10: `from /net/http.rb:1506:in `catch``
     9: `from /net/http.rb:1507:in `block in transport_request``
     8: `from /net/http/generic_request.rb:123:in `exec``
     7: `from /net/http/generic_request.rb:189:in `send_request_with_body``
     6: `from /net/protocol.rb:221:in `write``
     5: `from /net/protocol.rb:239:in `writing``
     4: `from /net/protocol.rb:222:in `block in write``
     3: `from /net/protocol.rb:249:in `write0``
     2: `from /net/protocol.rb:249:in `each_with_index``
     1: `from /net/protocol.rb:249:in `each``
`/net/protocol.rb:270:in `block in write0`: Net::WriteTimeout (Net::WriteTimeout)`

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.