How do you set the timeout for blocking operations on a Ruby socket?
-
3Found a much better solution than your accepted one here: http://stackoverflow.com/a/12111120/216314 – Tyler Brock Sep 02 '12 at 21:28
-
http://ruby-doc.org/stdlib/libdoc/timeout/rdoc/Timeout.html – Todd A. Jacobs Oct 10 '15 at 00:17
-
[Timeout module with exclusive locks](http://stackoverflow.com/a/15304835/1301972). – Todd A. Jacobs Oct 10 '15 at 00:19
3 Answers
The solution I found which appears to work is to use Timeout::timeout:
require 'timeout'
...
begin
timeout(5) do
message, client_address = some_socket.recvfrom(1024)
end
rescue Timeout::Error
puts "Timed out!"
end

- 343,444
- 107
- 203
- 205
-
15Using timeout is a mistake. Due to green theards, anything that blocks on IO will block the timeout thread as well thus stopping it from working. – Sardathrion - against SE abuse Dec 07 '10 at 16:33
-
@Sardathrion, thanks for the feedback but a solution would be better than a negative comment :) – Mike Aug 29 '11 at 22:43
-
1Ruby threads are broken I am afraid. Find a better language -- harsh but true. – Sardathrion - against SE abuse Aug 30 '11 at 06:45
-
2The SystemTimer gem can be used to implement safe timeouts on Ruby 1.8. Ruby 1.9 does not have the timeout limitation described by Sardathrion since it uses native threads. – betamatt Mar 26 '12 at 19:22
-
3This uses threads for timeouts which is very bad for performance in multithreaded applications in ruby. See my answer here: http://stackoverflow.com/a/12111120/216314 – Tyler Brock Aug 24 '12 at 14:19
-
@TylerBrock I am using Rails 3 with Apache/Passenger, which from my understanding is not multithreaded. I think Passenger spawns a new process for each request. Is your solution still recommended over this? – JohnMerlino Jul 12 '14 at 18:39
-
Can anyone confirm that the `Timeout::timeout` implementation above is reasonable for ruby 1.9.x and newer? – Blake Aug 26 '14 at 08:32
-
It is only reasonable if performance is not an issue but yes, this is perfectly reasonable Ruby code. The nuance is in the details of the implementation of the language. – Tyler Brock May 30 '16 at 08:16
-
Ruby 2.x is not using green threads anymore, so all the comments of this not working should be invalid now. – Lothar Jan 18 '22 at 02:54
The timeout object is a good solution.
This is an example of asynchronous I/O (non-blocking in nature and occurs asynchronously to the flow of the application.)
IO.select(read_array
[, write_array
[, error_array
[, timeout]]] ) => array or nil
Can be used to get the same effect.
require 'socket'
strmSock1 = TCPSocket::new( "www.dn.se", 80 )
strmSock2 = TCPSocket::new( "www.svd.se", 80 )
# Block until one or more events are received
#result = select( [strmSock1, strmSock2, STDIN], nil, nil )
timeout=5
timeout=100
result = select( [strmSock1, strmSock2], nil, nil,timeout )
puts result.inspect
if result
for inp in result[0]
if inp == strmSock1 then
# data avail on strmSock1
puts "data avail on strmSock1"
elsif inp == strmSock2 then
# data avail on strmSock2
puts "data avail on strmSock2"
elsif inp == STDIN
# data avail on STDIN
puts "data avail on STDIN"
end
end
end
I think the non blocking approach is the way to go.
I tried the mentioned above article and could still get it to hang.
this article non blocking networking and the jonke's approach above got me on the right path. My server was blocking on the initial connect so I needed it to be a little lower level.
the socket rdoc can give more details into the connect_nonblock
def self.open(host, port, timeout=10)
addr = Socket.getaddrinfo(host, nil)
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
rescue Errno::EINPROGRESS
resp = IO.select([sock],nil, nil, timeout.to_i)
if resp.nil?
raise Errno::ECONNREFUSED
end
begin
sock.connect_nonblock(Socket.pack_sockaddr_in(port, addr[0][3]))
rescue Errno::EISCONN
end
end
sock
end
to get a good test. startup a simple socket server and then do a ctrl-z to background it
the IO.select is expecting data to come in on the input stream within 10 seconds. this may not work if that is not the case.
It should be a good replacement for the TCPSocket's open method.

- 1,656
- 19
- 13
-
This works for me very well indeed. Timeout should not be used under any circumstances because of MRI's green threads. – Sardathrion - against SE abuse Dec 07 '10 at 16:23
-
3A non-blocking connect comes up writable when ready. Use `IO.select(nil,[sock],nil, timeout.to_i)` – tmm1 Jan 11 '12 at 01:33