Timeouts for popular Ruby gems
An unresponsive service can be worse than a down one. It can tie up your entire system if not handled properly. All network requests should have a timeout.
Here’s how to add timeouts for popular Ruby gems. All have been tested. You should avoid Ruby’s Timeout
module. The default is no timeout, unless otherwise specified. Enjoy!
Also available for Python, Node, Go, PHP, and Rust
For many apps, the single most important thing to do (if you use a relational database)
Standard Library
Data Stores
HTTP Clients
Commands
Web Servers
Rack Middleware
Solvers
Distributed Locks
3rd Party Services
Other
Prevent single queries from taking up all of your database’s resources.
If you use Rails, add to your config/database.yml
production:
variables:
statement_timeout: 5s # or ms, min, etc
or set it on your database role
ALTER ROLE myuser SET statement_timeout = '5s';
Test with
SELECT pg_sleep(6);
To set for a single transaction, use
BEGIN;
SET LOCAL statement_timeout = '5s';
...
COMMIT;
For migrations, you likely want to set a longer statement timeout. You can do this with
production:
variables:
statement_timeout: <%= ENV["STATEMENT_TIMEOUT"] || "5s" %>
And use
STATEMENT_TIMEOUT=90s rails db:migrate
Note: Requires MySQL 5.7.8 or higher, and only applies to read-only SELECT
statements (more info).
If you use Rails, add to your config/database.yml
production:
variables:
max_execution_time: 5000 # ms
or set it directly on each connection
SET SESSION max_execution_time = 5000;
Test with
SELECT 1 FROM information_schema.tables WHERE sleep(6);
To set for a single statement, use an optimizer hint
SELECT /*+ MAX_EXECUTION_TIME(5000) */ ...
Note: Requires MariaDB 10.1.1 or higher
If you use Rails, add to your config/database.yml
production:
variables:
max_statement_time: 5 # sec
or set it directly on each connection
SET SESSION max_statement_time = 5;
Test with
SELECT 1 FROM information_schema.tables WHERE sleep(6);
As of MariaDB 10.1.2, you can set single statement timeouts with
SET STATEMENT max_statement_time=5 FOR
SELECT ...
For migrations, you likely want to set a longer statement timeout. You can do this with
production:
variables:
max_statement_time: <%= ENV['MAX_STATEMENT_TIME'] || 5 %>
And use
MAX_STATEMENT_TIME=90 rails db:migrate
Note: Requires Ruby 3.2+
STDIN.timeout = 1
Raises IO::TimeoutError
Net::FTP.new(host, open_timeout: 1, read_timeout: 1)
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutNet::HTTP.start(host, port, open_timeout: 1, read_timeout: 1, write_timeout: 1) do
# ...
end
or
http = Net::HTTP.new(host, port)
http.open_timeout = 1
http.read_timeout = 1
http.write_timeout = 1
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutNet::WriteTimeout
on write timeoutDefault: 60s connect timeout, 60s read timeout, 60s write timeout
Write timeout can be set in Ruby 2.6+. Read timeouts are retried once automatically for idempotent methods like GET
. In Ruby 2.5+, you can set the number of retries with http.max_retries = 1
.
Net::IMAP.new(host, open_timeout: 1)
Read timeout is not configurable at the moment
Raises Net::OpenTimeout
on connect timeout
pop = Net::POP.new(host)
pop.open_timeout = 1
pop.read_timeout = 1
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutsmtp = Net::SMTP.new(host, 25)
smtp.open_timeout = 1
smtp.read_timeout = 1
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutURI.parse(url).open(open_timeout: 1, read_timeout: 1)
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutNote: Requires Ruby 3.2+
Regexp.timeout = 1
# or
Regexp.new(regexp, timeout: 1)
Raises Regexp::TimeoutError
ActiveRecord::Base.establish_connection(connect_timeout: 1, checkout_timeout: 1, ...)
or in config/database.yml
production:
connect_timeout: 1
checkout_timeout: 1
Raises
ActiveRecord::ConnectionNotEstablished
on connect and read timeouts for Active Record 6.1+PG::ConnectionBad
on connect and read timeouts for Active Record < 6.1ActiveRecord::ConnectionTimeoutError
on checkout timeoutSee also PostgreSQL statement timeouts
ActiveRecord::Base.establish_connection(connect_timeout: 1, read_timeout: 1, write_timeout: 1, checkout_timeout: 1, ...)
or in config/database.yml
production:
connect_timeout: 1
read_timeout: 1
write_timeout: 1
checkout_timeout: 1
Raises
ActiveRecord::ConnectionNotEstablished
on connect and read timeouts for Active Record 6.1+Mysql2::Error
on connect and read timeouts for Active Record < 6.1ActiveRecord::ConnectionTimeoutError
on checkout timeoutSee also MySQL statement timeouts
Bunny.new(connection_timeout: 1, read_timeout: 1, ...)
Raises
Bunny::TCPConnectionFailedForAllHosts
on connect timeoutBunny::NetworkFailure
on read timeoutCassandra.cluster(connect_timeout: 1, timeout: 1)
Default: 10s connect timeout, 12s read timeout
Raises
Cassandra::Errors::NoHostsAvailable
on connect timeoutCassandra::Errors::TimeoutError
on read timeoutConnectionPool.new(timeout: 1) { ... }
Raises ConnectionPool::TimeoutError
CouchRest.new(url, open_timeout: 1, read_timeout: 1, timeout: 1)
Raises
HTTPClient::ConnectTimeoutError
on connect timeoutHTTPClient::ReceiveTimeoutError
on read timeoutDalli::Client.new(host, socket_timeout: 1, ...)
Default: 1s
Raises Dalli::RingError
Drill.new(url: url, open_timeout: 1, read_timeout: 1)
Default: 3s connect timeout, no read timeout
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutElasticsearch::Client.new(transport_options: {request: {timeout: 1}}, ...)
Raises Elastic::Transport::Transport::Error
conn = Hiredis::Connection.new
conn.timeout = 1_000_000 # microseconds
Raises
Errno::ETIMEDOUT
on connect timeoutErrno::EAGAIN
on read timeoutImmudb::Client.new(host, timeout: 1)
Raises GRPC::DeadlineExceeded
InfluxDB::Client.new(open_timeout: 1, read_timeout: 1)
Raises InfluxDB::ConnectionError
InfluxDB2::Client.new(url, token, open_timeout: 1, read_timeout: 1)
Raises InfluxDB2::InfluxError
MeiliSearch::Client.new(url, api_key, timeout: 1)
Raises MeiliSearch::TimeoutError
Mongo::Client.new([host], connect_timeout: 1, socket_timeout: 1, server_selection_timeout: 1, ...)
Raises Mongo::Error::NoServerAvailable
production:
clients:
default:
options:
connect_timeout: 1
socket_timeout: 1
server_selection_timeout: 1
Raises Mongo::Error::NoServerAvailable
Mysql2::Client.new(connect_timeout: 1, read_timeout: 1, write_timeout: 1, ...)
Raises Mysql2::Error
config.neo4j.session.options = {
faraday_configurator: lambda do |faraday|
faraday.adapter :typhoeus
faraday.options[:open_timeout] = 5
faraday.options[:timeout] = 65
end
}
Raises Faraday::TimeoutError
PG.connect(connect_timeout: 1, ...)
Raises PG::ConnectionBad
Presto::Client.new(http_open_timeout: 1, http_timeout: 1)
Raises
Faraday::ConnectionFailed
on connect timeoutFaraday::TimeoutError
on read timeoutRedis.new(connect_timeout: 1, timeout: 1, ...)
Default: 1s after 5.0, 5s before
Raises
Redis::CannotConnectError
on connect timeoutRedis::TimeoutError
on read timeoutRedisClient.config(timeout: 1, ...)
# or
RedisClient.config(connect_timeout: 1, read_timeout: 1, write_timeout: 1, ...)
Default: 1s
Raises RedisClient::CannotConnectError
client = Riddle::Client.new
client.timeout = 1
Raises Riddle::ResponseError
RSolr.connect(open_timeout: 1, timeout: 1)
Raises
RSolr::Error::ConnectionRefused
on connect timeoutRSolr::Error::Timeout
on read timeoutNot configurable at the moment
Default: 10s connect timeout, no read timeout
Kafka.new(connect_timeout: 1, socket_timeout: 1)
Raises Kafka::ConnectionError
Searchkick.timeout = 1
Searchkick.search_timeout = 1
Default: 10s
Raises same exceptions as elasticsearch
Sequel.connect(connect_timeout: 1, pool_timeout: 1, ...)
Raises
Sequel::DatabaseConnectionError
on connect and read timeoutsSequel::PoolTimeout
on checkout timeoutSequel.connect(timeout: 1, read_timeout: 1, connect_timeout: 1, pool_timeout: 1, ...)
Raises
Sequel::DatabaseConnectionError
on connect and read timeoutsSequel::PoolTimeout
on checkout timeoutTrino::Client.new(http_open_timeout: 1, http_timeout: 1)
Raises
Faraday::ConnectionFailed
on connect timeoutFaraday::TimeoutError
on read timeoutTypesense::Client.new(connection_timeout_seconds: 1)
Raises Typesense::Error::TimeoutError
curl = Curl::Easy.new(url)
curl.connect_timeout = 1
curl.timeout = 1
curl.perform
Raises Curl::Err::TimeoutError
Down::NetHttp.download(connect_url, open_timeout: 1, read_timeout: 1)
Raises Down::TimeoutError
EventMachine.run do
http = EventMachine::HttpRequest.new(url, connect_timeout: 1, inactivity_timeout: 1).get
http.errback { http.error }
end
No exception is raised, but http.error
is set to Errno::ETIMEDOUT
in http.errback
.
Excon.get(url, connect_timeout: 1, read_timeout: 1, write_timeout: 1)
Raises Excon::Errors::Timeout
Faraday.get(url) do |req|
req.options.open_timeout = 1
req.options.timeout = 1
end
or
Faraday.new(url, request: {open_timeout: 1, timeout: 1}) do |faraday|
# ...
end
Raises
Faraday::ConnectionFailed
on connect timeoutFaraday::TimeoutError
on read timeoutHTTP.timeout(connect: 1, read: 1, write: 1).get(url)
Raises
HTTP::ConnectTimeoutError
on connect timeoutHTTP::TimeoutError
on read timeoutHTTParty.get(url, timeout: 1)
or
class Resource
include HTTParty
default_timeout 1
# or
open_timeout 1
read_timeout 1
write_timeout 1
end
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutclient = HTTPClient.new
client.connect_timeout = 1
client.receive_timeout = 1
client.send_timeout = 1
client.get(url)
Raises
HTTPClient::ConnectTimeoutError
on connect timeoutHTTPClient::ReceiveTimeoutError
on read timeoutHTTPI::Request.new(url: url, open_timeout: 1)
Raises same errors as underlying client
sess = Patron::Session.new
sess.connect_timeout = 1
sess.timeout = 1
Raises Patron::TimeoutError
RestClient::Request.execute(method: :get, url: url, open_timeout: 1, read_timeout: 1)
# shorthand to set open_timeout = read_timeout = 1
RestClient::Request.execute(method: :get, url: url, timeout: 1)
Same options also work with RestClient::Resource
.
Raises
RestClient::Exceptions::OpenTimeout
on connect timeoutRestClient::Exceptions::ReadTimeout
on read timeoutDefault: 60s connect timeout, 60s read timeout
response = Typhoeus.get(url, connecttimeout: 1, timeout: 1)
No exception is raised. Check for a timeout with
response.timed_out?
Unirest.timeout(1)
Connect timeout is not configurable
Default: 10s read timeout, no connect timeout
Raises RuntimeError
Frontkick.exec(command, timeout: 1)
Raises Frontkick::Timeout
Mixlib::ShellOut.new(command, timeout: 1)
Raises Mixlib::ShellOut::CommandTimeout
POSIX::Spawn::Child.new(command, timeout: 1)
Raises POSIX::Spawn::TimeoutExceeded
TTY::Command.new(timeout: 1)
or
cmd.run(command, timeout: 1)
Raises TTY::Command::TimeoutExceeded
# config/puma.rb
worker_timeout 15
Default: 60s
This kills and respawns the worker process. Note that this is for the worker and not threads. This isn’t a request timeout either. Use Rack middleware for request timeouts.
# config/puma.rb
worker_shutdown_timeout 8
Default: 30s
This causes Puma to send a SIGKILL signal to a worker if it hasn’t shutdown within the specified time period after having received a SIGTERM signal.
# config/unicorn.rb
timeout 15
Default: 60s
This kills and respawns the worker process.
It’s recommended to use this in addition to Rack middleware.
use Rack::Timeout,
service_timeout: 15, # ENV["RACK_TIMEOUT_SERVICE_TIMEOUT"]
wait_timeout: 30, # ENV["RACK_TIMEOUT_WAIT_TIMEOUT"]
wait_overtime: 60, # ENV["RACK_TIMEOUT_WAIT_OVERTIME"]
service_past_wait: false, # ENV["RACK_TIMEOUT_SERVICE_PAST_WAIT"]
term_on_timeout: false # ENV["RACK_TIMEOUT_TERM_ON_TIMEOUT"]
Default: 15s service timeout, 30s wait timeout
Raises Rack::Timeout::RequestTimeoutError
or Rack::Timeout::RequestExpiryError
Note: The approach used by Rack::Timeout can leave your application in an inconsistent state, as described here. You can use term on timeout to avoid this.
Slowpoke.timeout = 5
Default: 15s
Raises same exceptions as rack-timeout
routing.solve(time_limit: 1)
solver.solve(p, q, a, l, u, time_limit: 1)
Check for a status
of run time limit reached
for a timeout
problem.set_time_limit(1)
or
problem.solve(sec: 1)
Check for a timeout with
problem.time_limit_reached?
solver.solve(data, cone, time_limit_secs: 1)
Check for a status
of solved (inaccurate - reached time_limit_secs)
for a timeout
ActiveRecord::Base.connection.get_advisory_lock(123)
Returns false
if lock cannot be immediately acquired
redis.lock(key, life: 1, acquire: 1) do |lock|
# ...
end
Default: 10s acquisition timeout
Raises Redis::Lock::LockNotAcquired
lock_manager.lock!(key, 1000) do
# ...
end
Default: 200ms acquisition timeout with 3 retries
Raises Redlock::LockError
Suo::Client::Memcached.new(key, acquisition_timeout: 1)
or
Suo::Client::Redis.new(key, acquisition_timeout: 1)
Default: 0.1s acquisition timeout with 10 retries
The lock
method returns nil
on timeout
ActiveRecord::Base.with_advisory_lock("123", timeout_seconds: 1) do
# ...
end
Returns false
on acquisition timeout
Not configurable at the moment, and no timeout by default
Airtable::Resource.default_timeout 1
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutAlgolia.init(
connect_timeout: 1,
send_timeout: 1,
receive_timeout: 1,
batch_timeout: 1,
search_timeout: 1
)
Raises Algolia::AlgoliaProtocolError
Aws.config = {
http_open_timeout: 1,
http_read_timeout: 1
}
Or with a client
Aws::S3::Client.new(
http_open_timeout: 1,
http_read_timeout: 1
)
Raises Seahorse::Client::NetworkingError
Not configurable at the moment, and no timeout by default
Available since version 3.0.0:
adapter = Bitly::HTTP::Adapters::NetHTTP.new(request_opts: {
open_timeout: 1,
read_timeout: 1
})
http_client = Bitly::HTTP::Client.new(adapter)
client = Bitly::API::Client.new(token: token, http: http_client)
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutBoxr::BOX_CLIENT.connect_timeout = 1
Boxr::BOX_CLIENT.receive_timeout = 1
Boxr::BOX_CLIENT.send_timeout = 1
Raises
HTTPClient::ConnectTimeoutError
on connect timeoutHTTPClient::ReceiveTimeoutError
on read timeoutDefault: 30s connect timeout, 60s read timeout
Not configurable at the moment
Clearbit::Resource.options = {timeout: 1}
Raises Nestful::TimeoutError
timeout = 1
Dogapi::Client.new(api_key, nil, nil, nil, false, timeout)
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutNot configurable at the moment
Default: No connect timeout, 600s read timeout
DropletKit::Client.new(open_timeout: 1, timeout: 1)
Raises
Faraday::ConnectionFailed
on connect timeoutFaraday::TimeoutError
on read timeoutNot configurable at the moment, and no timeout by default
firebase = Firebase::Client.new(url)
firebase.request.connect_timeout = 1
firebase.request.receive_timeout = 1
firebase.request.send_timeout = 1
Raises
HTTPClient::ConnectTimeoutError
on connect timeoutHTTPClient::ReceiveTimeoutError
on read timeoutNot configurable at the moment
Gibbon::Request.new(open_timeout: 1, timeout: 1, ...)
Raises Gibbon::MailChimpError
Github.new(connection_options: {request: {open_timeout: 1, timeout: 1}})
Raises
Faraday::ConnectionFailed
on connect timeoutFaraday::TimeoutError
on read timeoutGitlab.client(httparty: {timeout: 1})
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutclient = Google::Apis::DriveV2::DriveService.new
client.client_options.open_timeout_sec = 1
client.client_options.read_timeout_sec = 1
Raise Google::Apis::TransmissionError
Google::Cloud::Storage.new(timeout: 1)
Raises Google::Cloud::Error
[HipChat::Client, HipChat::Room, HipChat::User].each { |c| c.default_timeout(1) }
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutclient = Intercom::Client.new(token: token)
client.options(Intercom::Client.set_timeouts(open_timeout: 1, read_timeout: 1))
Raises
Intercom::ServiceConnectionError
on connect timeout (inherits from Intercom::IntercomError
)Intercom::ServiceUnavailableError
on read timeout (inherits from Intercom::IntercomError
)JIRA::Client.new(read_timeout: 1)
Connect timeout is not configurable at the moment
Raises Net::ReadTimeout
on read timeout
Koala.http_service.http_options = {request: {open_timeout: 1, timeout: 1}}
Raises Faraday::ConnectionFailed
Not configurable at the moment, and no timeout by default.
Octokit::Client.new(connection_options: {request: {open_timeout: 1, timeout: 1}})
Raises
Faraday::ConnectionFailed
on connect timeoutFaraday::TimeoutError
on read timeoutPinterest::Client.new(access_token, request: {open_timeout: 1, timeout: 1})
Raises
Faraday::ConnectionFailed
on connect timeoutFaraday::TimeoutError
on read timeoutclient.timeout = 1
# or
client.connect_timeout = 1
client.send_timeout = 1
client.receive_timeout = 1
client.keep_alive_timeout = 1
Raises Pusher::HTTPError
Pwned::Password.new("password", open_timeout: 1, read_timeout: 1)
Raises Pwned::TimeoutError
Restforce.new(timeout: 1)
Raises
Faraday::ConnectionFailed
on connect timeoutFaraday::TimeoutError
on read timeoutNot configurable at the moment, and no timeout by default
Not configurable at the moment, and no timeout by default
ShopifyAPI::Base.timeout = 1
Raises ActiveResource::TimeoutError
Sift::Client.new(timeout: 1)
Default: 2s
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutSlack::Notifier.new(webhook_url, http_options: {open_timeout: 1, read_timeout: 1})
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutSlack::Web::Client.new(open_timeout: 1, timeout: 1)
Raises Slack::Web::Api::Errors::TimeoutError
SmartyStreets::ClientBuilder.new(credentials).with_max_timeout(1)
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutSODA::Client.new(timeout: 1)
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutNot configurable at the moment, and no timeout by default
Stripe.open_timeout = 1
Stripe.read_timeout = 1
Default: 30s connect timeout, 80s read timeout
Raises Stripe::APIConnectionError
Tamber.open_timeout = 1
Tamber.read_timeout = 1
Raises Tamber::NetworkError
http_client = Twilio::HTTP::Client.new(timeout: 1)
Twilio::REST::Client.new(account_sid, auth_token, nil, nil, http_client)
Default: 30s
Raises Twilio::REST::TwilioError
Twitter::REST::Client.new do |config|
config.timeouts = {connect: 1, read: 1, write: 1}
end
Raises HTTP::TimeoutError
Note: All three timeouts must be set for any to take effect.
Not configurable at the moment, and no timeout by default
ZendeskAPI::Client.new do |config|
config.client_options = {request: {open_timeout: 1, timeout: 1}}
end
Default: 10s connect timeout, no read timeout
Raises ZendeskAPI::Error::NetworkError
Acme::Client.new(connection_options: {request: {open_timeout: 1, timeout: 1}})
Raises Acme::Client::Error::Timeout
ActionMailer::Base.smtp_settings = {
open_timeout: 1,
read_timeout: 1
}
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutActiveMerchant::Billing::Gateway.open_timeout = 1
ActiveMerchant::Billing::Gateway.read_timeout = 1
Default: 60s
Raises ActiveMerchant::ConnectionError
class Person < ActiveResource::Base
self.open_timeout = 1
self.read_timeout = 1
end
Raises ActiveResource::TimeoutError
client = ActiveShipping::USPS.new(login: "developer-key")
client.open_timeout = 1
client.read_timeout = 1
Default: 2s connect timeout, 10s read timeout
Raises ActiveUtils::ConnectionError
Carrot2.new(open_timeout: 1, read_timeout: 1)
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutDocker.options = {
connect_timeout: 1,
read_timeout: 1
}
Raises Docker::Error::TimeoutError
client = Etcd.client(read_timeout: 1)
Connect timeout not configurable
Default: 60s read timeout
Raises
Net::ReadTimeout
on read timeoutEtcdv3.new(command_timeout: 1)
or
conn.get(key, timeout: 1)
Raises GRPC::DeadlineExceeded
FastImage.size(url, timeout: 1)
Returns nil
on timeouts
If you pass raise_on_failure: true
, raises FastImage::ImageFetchFailure
Geocoder.configure(timeout: 1, ...)
No exception is raised by default. To raise exceptions, use
Geocoder.configure(timeout: 1, always_raise: :all, ...)
Raises Geocoder::LookupTimeout
GraphQL::Client::HTTP.new(url) do
def connection
conn = super
conn.open_timeout = 1
conn.read_timeout = 1
conn
end
end
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutRouteGuide::Stub.new(addr, :this_channel_is_insecure, timeout: 1)
Raises GRPC::DeadlineExceeded
Hexspace::Client.new(timeout: 1)
Raises Thrift::TransportException
Ignite::Client.new(connect_timeout: 1)
Read timeout is not configurable at the moment
Raises Ignite::TimeoutError
on connect timeout
Kubeclient::Client.new(url, timeouts: {open: 1, read: 1})
Raises KubeException
Default: 60s connect timeout, 60s read timeout
Mail.defaults do
delivery_method :smtp, open_timeout: 1, read_timeout: 1
end
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutagent = Mechanize.new
agent.open_timeout = 1
agent.read_timeout = 1
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutnats = NATS::IO::Client.new
nats.connect(connect_timeout: 1)
Raises NATS::IO::SocketTimeoutError
Nestful::Request.new(url, timeout: 1)
or
class Resource < Nestful::Resource
options timeout: 1
end
Raises Nestful::TimeoutError
Net::DNS::Resolver.new(udp_timeout: 1)
Default: 5s
Raises Net::DNS::Resolver::NoResponseError
Net::LDAP.new(host: host, connect_timeout: 1)
Read timeout not configurable at the moment
Default: 5s connect timeout, no read timeout
Raises Net::LDAP::Error
timeout = 1
Net::NTP.get(host, port, timeout)
Raises Timeout::Error
Net::SCP.start(host, user, timeout: 1)
Raises Net::SSH::ConnectionTimeout
Net::SFTP.start(host, user, timeout: 1)
Raises Net::SSH::ConnectionTimeout
Net::SSH.start(host, user, timeout: 1)
Raises Net::SSH::ConnectionTimeout
Net::Telnet::new("Host" => host, "Timeout" => 1)
Raises
Net::OpenTimeout
on connect timeoutNet::ReadTimeout
on read timeoutNot configurable at the moment, and no timeout by default
RBHive.tcli_connect(host, port, timeout: 1) do |connection|
# ...
end
Raises Thrift::TransportException
Reversed.lookup("8.8.8.8", timeout: 1)
Returns nil
on timeouts
Savon.client(wsdl: url, open_timeout: 1, read_timeout: 1)
Raises
HTTPClient::ConnectTimeoutError
on connect timeoutHTTPClient::ReceiveTimeoutError
on read timeoutSocket.tcp(host, 80, connect_timeout: 1) do |sock|
# ...
end
Raises Errno::ETIMEDOUT
Spidr.open_timeout = 1
Spidr.read_timeout = 1
No exception is raised. Check for failures with
agent = Spidr.site(url)
agent.failures
Spyke::Base.connection = Faraday.new(url: url) do |c|
c.adapter Faraday.default_adapter
c.options[:open_timeout] = 1
c.options[:timeout] = 1
end
Raises Spyke::ConnectionError
Stomp::Client.new(start_timeout: 1, connect_timeout: 1, connread_timeout: 1, parse_timeout: 1)
Raises
Stomp::Error::StartTimeoutException
on connect timeoutStomp::Error::ReceiveTimeout
on read timeoutThrift::Socket.new(host, port, 1)
Raises Thrift::TransportException
ThriftClient.new(client_class, servers, connect_timeout: 1, timeout: 1)
Raises
ThriftClient::NoServersAvailable
on connect timeoutVault.configure do |config|
config.timeout = 1
# or more granular
config.ssl_timeout = 1
config.open_timeout = 1
config.read_timeout = 1
end
Raises Vault::HTTPConnectionError
Whois::Client.new(timeout: 1)
Default: 10s
Raises Timeout::Error
Not configurable at the moment
Default: 30s
Raises Zookeeper::Exceptions::ContinuationTimeoutError
Not configurable at the moment
Default: 30s
Raises Zookeeper::Exceptions::ContinuationTimeoutError
Let us know. Even better, create a pull request for it.
Take advantage of inheritance. Instead of
rescue Net::OpenTimeout, Net::ReadTimeout
you can do
rescue Timeout::Error
Use
Timeout::Error
for both Net::OpenTimeout
and Net::ReadTimeout
Faraday::ClientError
for both Faraday::ConnectionFailed
and Faraday::TimeoutError
HTTPClient::TimeoutError
for both HTTPClient::ConnectTimeoutError
and HTTPClient::ReceiveTimeoutError
Redis::BaseConnectionError
for both Redis::CannotConnectError
and Redis::TimeoutError
Rack::Timeout::Error
for both Rack::Timeout::RequestTimeoutError
and Rack::Timeout::RequestExpiryError
RestClient::Exceptions::Timeout
for both RestClient::Exceptions::OpenTimeout
and RestClient::Exceptions::ReadTimeout
Adding timeouts to existing services can be a daunting task, but there’s a low risk way to do it.
git clone https://github.com/ankane/the-ultimate-guide-to-ruby-timeouts.git
cd the-ultimate-guide-to-ruby-timeouts
bundle install
To run all tests, use:
bundle exec appraisal rake test
To run individual tests, use:
bundle exec appraisal faraday rake test
To add a new gem:
Appraisals
and run bundle exec appraisal generate
bundle exec appraisal new_gem bundle
test/new_gem_test.rb
and run bundle exec appraisal new_gem rake test
Because time is not going to go backwards, I think I better stop now. - Stephen Hawking
🕓