BigBinary Blog

We write about Ruby on Rails, React.js, React Native, remote work, open source, engineering and design.

Ruby 2.6 adds write_timeout to Net::HTTP

This blog is part of our Ruby 2.6 series.

Ruby 2.6.0 was released on Dec 25, 2018.

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.

Taha Husain in Ruby 2.6
14, 2018
Share

You might also like

MJIT Support in Ruby 2.6

Ruby 2.6 Range#cover? accepts Range object as argument

Ruby 2.6 adds RubyVM::AST module

Ruby 2.6 adds Enumerable#filter as alias of Enumerable#select

Ruby 2.6 adds support for non-ASCII capital letter

Subscribe to our newsletter