The Ultimate Guide to Ruby Timeouts
December 19, 2025 · View on GitHub
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
Timeout Types
- connect (or open) - time to open the connection
- read (or receive) - time to receive data after connected
- write (or send) - time to send data after connected
- checkout - time to checkout a connection from the pool
- statement - time to execute a database statement
- lock (or acquisition) - time to acquire a lock
- request (or service) - time to process a request
- wait - time to start processing a queued request
- command - time to run a command
- solve - time to solve an optimization problem
Statement Timeouts
For many apps, the single most important thing to do (if you use a relational database)
Gems
Standard Library
Data Stores
- activerecord
- bunny
- cassandra-driver
- connection_pool
- couchrest
- dalli
- drill-sergeant
- elasticsearch
- hiredis
- immudb
- influxdb
- influxdb-client
- meilisearch
- mongo
- mongoid
- mysql2
- neo4j
- pg
- presto-client
- redis
- redis-client
- riddle
- rsolr
- ruby-druid
- ruby-kafka
- searchkick
- sequel
- trino-client
- typesense
HTTP Clients
Commands
Web Servers
Rack Middleware
Solvers
Distributed Locks
3rd Party Services
- airrecord
- airtable
- algoliasearch
- aws-sdk
- azure
- bitly
- boxr
- checkr-official
- clearbit
- dogapi
- dropbox-sdk
- droplet_kit
- fastly
- firebase
- flickraw
- gibbon
- github_api
- gitlab
- google-api-client
- google-cloud
- intercom
- jira-ruby
- koala
- octokit
- pusher
- pwned
- restforce
- rspotify
- ruby-trello
- sentry-ruby
- shopify_api
- sift
- slack-notifier
- slack-ruby-client
- smartystreets_ruby_sdk
- soda-ruby
- soundcloud
- stripe
- tamber
- twilio-ruby
- yt
- zendesk_api
Other
- acme-client
- actionmailer
- activemerchant
- activeresource
- carrot2
- docker-api
- etcd
- etcdv3
- fastimage
- geocoder
- graphql-client
- grpc
- hexspace
- ignite-client
- kubeclient
- mechanize
- nats-pure
- nestful
- net-dns
- net-ldap
- net-ntp
- net-scp
- net-sftp
- net-ssh
- net-telnet
- omniauth-oauth2
- rbhive
- reversed
- savon
- spidr
- spyke
- stomp
- thrift
- thrift_client
- vault
- whois
- zk
- zookeeper
Statement Timeouts
Prevent single queries from taking up all of your database’s resources.
PostgreSQL
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
MySQL
Note: 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) */ ...
MariaDB
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);
To set for a single statement, use
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
Standard Library
io
Note: Requires Ruby 3.2+
STDIN.timeout = 1
Raises IO::TimeoutError
net/ftp
Net::FTP.new(host, open_timeout: 1, read_timeout: 1)
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
net/http
Net::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::OpenTimeouton connect timeoutNet::ReadTimeouton read timeoutNet::WriteTimeouton write timeout
Default: 60s connect timeout, 60s read timeout, 60s write timeout
Read timeouts are retried once automatically for idempotent methods like GET. You can set the max number of retries with http.max_retries = 1.
net/imap
Net::IMAP.new(host, open_timeout: 1)
Read timeout is not configurable at the moment
Raises Net::OpenTimeout on connect timeout
net/pop
pop = Net::POP.new(host)
pop.open_timeout = 1
pop.read_timeout = 1
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
net/smtp
smtp = Net::SMTP.new(host, 25)
smtp.open_timeout = 1
smtp.read_timeout = 1
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
open-uri
URI.parse(url).open(open_timeout: 1, read_timeout: 1)
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
regexp
Note: Requires Ruby 3.2+
Regexp.timeout = 1
# or
Regexp.new(regexp, timeout: 1)
Raises Regexp::TimeoutError
socket
Socket.tcp(host, 80, connect_timeout: 1) do |sock|
# ...
end
Raises Errno::ETIMEDOUT
Data Stores
activerecord
-
postgres adapter
ActiveRecord::Base.establish_connection(connect_timeout: 1, checkout_timeout: 1, ...)or in
config/database.ymlproduction: connect_timeout: 1 checkout_timeout: 1Raises
ActiveRecord::ConnectionNotEstablishedon connect and read timeoutsActiveRecord::ConnectionTimeoutErroron checkout timeout
See also PostgreSQL statement timeouts
-
mysql2 adapter
ActiveRecord::Base.establish_connection(connect_timeout: 1, read_timeout: 1, write_timeout: 1, checkout_timeout: 1, ...)or in
config/database.ymlproduction: connect_timeout: 1 read_timeout: 1 write_timeout: 1 checkout_timeout: 1Raises
ActiveRecord::ConnectionNotEstablishedon connect and read timeoutsActiveRecord::ConnectionTimeoutErroron checkout timeout
See also MySQL statement timeouts
bunny
Bunny.new(connection_timeout: 1, read_timeout: 1, ...)
Raises
Bunny::TCPConnectionFailedForAllHostson connect timeoutBunny::NetworkFailureon read timeout
cassandra-driver
Cassandra.cluster(connect_timeout: 1, timeout: 1)
Default: 10s connect timeout, 12s read timeout
Raises
Cassandra::Errors::NoHostsAvailableon connect timeoutCassandra::Errors::TimeoutErroron read timeout
connection_pool
ConnectionPool.new(timeout: 1) { ... }
Raises ConnectionPool::TimeoutError
couchrest
CouchRest.new(url, open_timeout: 1, read_timeout: 1, timeout: 1)
Raises
HTTPClient::ConnectTimeoutErroron connect timeoutHTTPClient::ReceiveTimeoutErroron read timeout
dalli
Dalli::Client.new(host, socket_timeout: 1, ...)
Default: 1s
Raises Dalli::RingError
drill-sergeant
Drill.new(url: url, open_timeout: 1, read_timeout: 1)
Default: 3s connect timeout, no read timeout
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
elasticsearch
Elasticsearch::Client.new(transport_options: {request: {timeout: 1}}, ...)
Raises Elastic::Transport::Transport::Error
hiredis
conn = Hiredis::Connection.new
conn.timeout = 1_000_000 # microseconds
Raises
Errno::ETIMEDOUTon connect timeoutErrno::EAGAINon read timeout
immudb
Immudb::Client.new(host, timeout: 1)
Raises GRPC::DeadlineExceeded
influxdb
InfluxDB::Client.new(open_timeout: 1, read_timeout: 1)
Raises InfluxDB::ConnectionError
influxdb-client
InfluxDB2::Client.new(url, token, open_timeout: 1, read_timeout: 1)
Raises InfluxDB2::InfluxError
meilisearch
Meilisearch::Client.new(url, api_key, timeout: 1)
Raises Meilisearch::TimeoutError
mongo
Mongo::Client.new([host], connect_timeout: 1, socket_timeout: 1, server_selection_timeout: 1, ...)
Raises Mongo::Error::NoServerAvailable
mongoid
production:
clients:
default:
options:
connect_timeout: 1
socket_timeout: 1
server_selection_timeout: 1
Raises Mongo::Error::NoServerAvailable
mysql2
Mysql2::Client.new(connect_timeout: 1, read_timeout: 1, write_timeout: 1, ...)
Raises Mysql2::Error
neo4j
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
PG.connect(connect_timeout: 1, ...)
Raises PG::ConnectionBad
presto-client
Presto::Client.new(http_open_timeout: 1, http_timeout: 1)
Raises
Faraday::ConnectionFailedon connect timeoutFaraday::TimeoutErroron read timeout
redis
Redis.new(connect_timeout: 1, timeout: 1, ...)
Default: 1s after 5.0, 5s before
Raises
Redis::CannotConnectErroron connect timeoutRedis::TimeoutErroron read timeout
redis-client
RedisClient.config(timeout: 1, ...)
# or
RedisClient.config(connect_timeout: 1, read_timeout: 1, write_timeout: 1, ...)
Default: 1s
Raises RedisClient::CannotConnectError
riddle
client = Riddle::Client.new
client.timeout = 1
Raises Riddle::ResponseError
rsolr
RSolr.connect(open_timeout: 1, timeout: 1)
Raises
RSolr::Error::ConnectionRefusedon connect timeoutRSolr::Error::Timeouton read timeout
ruby-druid
Not configurable at the moment
Default: 10s connect timeout, no read timeout
ruby-kafka
Kafka.new(connect_timeout: 1, socket_timeout: 1)
Raises Kafka::ConnectionError
searchkick
Searchkick.timeout = 1
Searchkick.search_timeout = 1
Default: 10s
Raises same exceptions as elasticsearch
sequel
-
postgres adapter
Sequel.connect(connect_timeout: 1, pool_timeout: 1, ...)Raises
Sequel::DatabaseConnectionErroron connect and read timeoutsSequel::PoolTimeouton checkout timeout
-
mysql2 adapter
Sequel.connect(timeout: 1, read_timeout: 1, connect_timeout: 1, pool_timeout: 1, ...)Raises
Sequel::DatabaseConnectionErroron connect and read timeoutsSequel::PoolTimeouton checkout timeout
trino-client
Trino::Client.new(http_open_timeout: 1, http_timeout: 1)
Raises
Faraday::ConnectionFailedon connect timeoutFaraday::TimeoutErroron read timeout
typesense
Typesense::Client.new(connection_timeout_seconds: 1)
Raises
Faraday::ConnectionFailedon connect timeoutFaraday::TimeoutErroron read timeout
HTTP Clients
curb
curl = Curl::Easy.new(url)
curl.connect_timeout = 1
curl.timeout = 1
curl.perform
Raises Curl::Err::TimeoutError
down
Down::NetHttp.download(connect_url, open_timeout: 1, read_timeout: 1)
Raises Down::TimeoutError
em-http-client
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
Excon.get(url, connect_timeout: 1, read_timeout: 1, write_timeout: 1)
Raises Excon::Errors::Timeout
faraday
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::ConnectionFailedon connect timeoutFaraday::TimeoutErroron read timeout
http
HTTP.timeout(connect: 1, read: 1, write: 1).get(url)
Raises
HTTP::ConnectTimeoutErroron connect timeoutHTTP::TimeoutErroron read timeout
httparty
HTTParty.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::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
httpclient
client = HTTPClient.new
client.connect_timeout = 1
client.receive_timeout = 1
client.send_timeout = 1
client.get(url)
Raises
HTTPClient::ConnectTimeoutErroron connect timeoutHTTPClient::ReceiveTimeoutErroron read timeout
httpi
HTTPI::Request.new(url: url, open_timeout: 1)
Raises same errors as underlying client
patron
sess = Patron::Session.new
sess.connect_timeout = 1
sess.timeout = 1
Raises Patron::TimeoutError
rest-client
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::OpenTimeouton connect timeoutRestClient::Exceptions::ReadTimeouton read timeout
Default: 60s connect timeout, 60s read timeout
typhoeus
response = Typhoeus.get(url, connecttimeout: 1, timeout: 1)
No exception is raised. Check for a timeout with
response.timed_out?
Commands
mixlib-shellout
Mixlib::ShellOut.new(command, timeout: 1)
Raises Mixlib::ShellOut::CommandTimeout
posix-spawn
POSIX::Spawn::Child.new(command, timeout: 1)
Raises POSIX::Spawn::TimeoutExceeded
tty-command
TTY::Command.new(timeout: 1)
or
cmd.run(command, timeout: 1)
Raises TTY::Command::TimeoutExceeded
Web Servers
puma
# 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.
unicorn
# 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.
Rack Middleware
rack-timeout
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
Slowpoke.timeout = 5
Default: 15s
Raises same exceptions as rack-timeout
Solvers
or-tools
routing.solve(time_limit: 1)
osqp
solver.solve(p, q, a, l, u, time_limit: 1)
Check for a status of run time limit reached for a timeout
ruby-cbc
problem.set_time_limit(1)
or
problem.solve(sec: 1)
Check for a timeout with
problem.time_limit_reached?
scs
solver.solve(data, cone, time_limit_secs: 1)
Check for a status of solved (inaccurate - reached time_limit_secs) for a timeout
Distributed Locks
activerecord
ActiveRecord::Base.connection.get_advisory_lock(123)
Returns false if lock cannot be immediately acquired
mlanett-redis-lock
redis.lock(key, life: 1, acquire: 1) do |lock|
# ...
end
Default: 10s acquisition timeout
Raises Redis::Lock::LockNotAcquired
redlock
lock_manager.lock!(key, 1000) do
# ...
end
Default: 200ms acquisition timeout with 3 retries
Raises Redlock::LockError
suo
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
with_advisory_lock
ActiveRecord::Base.with_advisory_lock("123", timeout_seconds: 1) do
# ...
end
Returns false on acquisition timeout
3rd Party Services
airrecord
Not configurable at the moment, and no timeout by default
airtable
Airtable::Resource.default_timeout 1
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
algoliasearch
Algolia.init(
connect_timeout: 1,
send_timeout: 1,
receive_timeout: 1,
batch_timeout: 1,
search_timeout: 1
)
Raises Algolia::AlgoliaProtocolError
aws-sdk
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
azure
Not configurable at the moment, and no timeout by default
bitly
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::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
boxr
Boxr::BOX_CLIENT.connect_timeout = 1
Boxr::BOX_CLIENT.receive_timeout = 1
Boxr::BOX_CLIENT.send_timeout = 1
Raises
HTTPClient::ConnectTimeoutErroron connect timeoutHTTPClient::ReceiveTimeoutErroron read timeout
checkr-official
Default: 30s connect timeout, 60s read timeout
Not configurable at the moment
clearbit
Clearbit::Resource.options = {timeout: 1}
Raises Nestful::TimeoutError
dogapi
timeout = 1
Dogapi::Client.new(api_key, nil, nil, nil, false, timeout)
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
dropbox-sdk
Not configurable at the moment
Default: No connect timeout, 600s read timeout
droplet_kit
DropletKit::Client.new(open_timeout: 1, timeout: 1)
Raises
Faraday::ConnectionFailedon connect timeoutFaraday::TimeoutErroron read timeout
fastly
Not configurable at the moment, and no timeout by default
firebase
firebase = Firebase::Client.new(url)
firebase.request.connect_timeout = 1
firebase.request.receive_timeout = 1
firebase.request.send_timeout = 1
Raises
HTTPClient::ConnectTimeoutErroron connect timeoutHTTPClient::ReceiveTimeoutErroron read timeout
flickraw
Not configurable at the moment
gibbon
Gibbon::Request.new(open_timeout: 1, timeout: 1, ...)
Raises Gibbon::MailChimpError
github_api
Github.new(connection_options: {request: {open_timeout: 1, timeout: 1}})
Raises
Faraday::ConnectionFailedon connect timeoutFaraday::TimeoutErroron read timeout
gitlab
Gitlab.client(httparty: {timeout: 1})
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
google-api-client
client = 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
Google::Cloud::Storage.new(timeout: 1)
Raises Google::Cloud::Error
intercom
client = Intercom::Client.new(token: token)
client.options(Intercom::Client.set_timeouts(open_timeout: 1, read_timeout: 1))
Raises
Intercom::ServiceConnectionErroron connect timeout (inherits fromIntercom::IntercomError)Intercom::ServiceUnavailableErroron read timeout (inherits fromIntercom::IntercomError)
jira-ruby
JIRA::Client.new(read_timeout: 1)
Connect timeout is not configurable at the moment
Raises Net::ReadTimeout on read timeout
koala
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
Octokit::Client.new(connection_options: {request: {open_timeout: 1, timeout: 1}})
Raises
Faraday::ConnectionFailedon connect timeoutFaraday::TimeoutErroron read timeout
pusher
client.timeout = 1
# or
client.connect_timeout = 1
client.send_timeout = 1
client.receive_timeout = 1
client.keep_alive_timeout = 1
Raises Pusher::HTTPError
pwned
Pwned::Password.new("password", open_timeout: 1, read_timeout: 1)
Raises Pwned::TimeoutError
restforce
Restforce.new(timeout: 1)
Raises
Faraday::ConnectionFailedon connect timeoutFaraday::TimeoutErroron read timeout
rspotify
Not configurable at the moment, and no timeout by default
ruby-trello
Not configurable at the moment, and no timeout by default
sentry-ruby
Sentry.init do |config|
config.transport.open_timeout = 1
config.transport.timeout = 1
end
Default: 1s connect timeout, 2s read/write timeout
Raises Sentry::ExternalError in some cases
shopify_api
Not configurable at the moment, and no timeout by default
sift
Sift::Client.new(timeout: 1)
Default: 2s
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
slack-notifier
Slack::Notifier.new(webhook_url, http_options: {open_timeout: 1, read_timeout: 1})
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
slack-ruby-client
Slack::Web::Client.new(open_timeout: 1, timeout: 1)
Raises Slack::Web::Api::Errors::TimeoutError
smartystreets_ruby_sdk
SmartyStreets::ClientBuilder.new(credentials).with_max_timeout(1)
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
soda-ruby
SODA::Client.new(timeout: 1)
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
soundcloud
Not configurable at the moment, and no timeout by default
stripe
Stripe.open_timeout = 1
Stripe.read_timeout = 1
Default: 30s connect timeout, 80s read timeout
Raises Stripe::APIConnectionError
tamber
Tamber.open_timeout = 1
Tamber.read_timeout = 1
Raises Tamber::NetworkError
twilio-ruby
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.
yt
Not configurable at the moment, and no timeout by default
zendesk_api
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
Other
acme-client
Acme::Client.new(connection_options: {request: {open_timeout: 1, timeout: 1}})
Raises Acme::Client::Error::Timeout
actionmailer
ActionMailer::Base.smtp_settings = {
open_timeout: 1,
read_timeout: 1
}
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
activemerchant
ActiveMerchant::Billing::Gateway.open_timeout = 1
ActiveMerchant::Billing::Gateway.read_timeout = 1
Default: 60s
Raises ActiveMerchant::ConnectionError
activeresource
class Person < ActiveResource::Base
self.open_timeout = 1
self.read_timeout = 1
end
Raises ActiveResource::TimeoutError
carrot2
Carrot2.new(open_timeout: 1, read_timeout: 1)
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
docker-api
Docker.options = {
connect_timeout: 1,
read_timeout: 1
}
Raises Docker::Error::TimeoutError
etcd
client = Etcd.client(read_timeout: 1)
Connect timeout not configurable
Default: 60s read timeout
Raises
Net::ReadTimeouton read timeout
etcdv3
Etcdv3.new(command_timeout: 1)
or
conn.get(key, timeout: 1)
Raises GRPC::DeadlineExceeded
fastimage
FastImage.size(url, timeout: 1)
Returns nil on timeouts
If you pass raise_on_failure: true, raises FastImage::ImageFetchFailure
geocoder
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
GraphQL::Client::HTTP.new(url) do
def connection
conn = super
conn.open_timeout = 1
conn.read_timeout = 1
conn
end
end
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
grpc
RouteGuide::Stub.new(addr, :this_channel_is_insecure, timeout: 1)
Raises GRPC::DeadlineExceeded
hexspace
Hexspace::Client.new(timeout: 1)
Raises Thrift::TransportException
ignite-client
Ignite::Client.new(connect_timeout: 1)
Read timeout is not configurable at the moment
Raises Ignite::TimeoutError on connect timeout
kubeclient
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::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
mechanize
agent = Mechanize.new
agent.open_timeout = 1
agent.read_timeout = 1
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
nats-pure
nats = NATS::IO::Client.new
nats.connect(connect_timeout: 1)
Raises NATS::IO::SocketTimeoutError
nestful
Nestful::Request.new(url, timeout: 1)
or
class Resource < Nestful::Resource
options timeout: 1
end
Raises Nestful::TimeoutError
net-dns
Net::DNS::Resolver.new(udp_timeout: 1)
Default: 5s
Raises Net::DNS::Resolver::NoResponseError
net-ldap
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
net-ntp
timeout = 1
Net::NTP.get(host, port, timeout)
Raises Timeout::Error
net-scp
Net::SCP.start(host, user, timeout: 1)
Raises Net::SSH::ConnectionTimeout
net-sftp
Net::SFTP.start(host, user, timeout: 1)
Raises Net::SSH::ConnectionTimeout
net-ssh
Net::SSH.start(host, user, timeout: 1)
Raises Net::SSH::ConnectionTimeout
net-telnet
Net::Telnet::new("Host" => host, "Timeout" => 1)
Raises
Net::OpenTimeouton connect timeoutNet::ReadTimeouton read timeout
omniauth-oauth2
Not configurable at the moment, and no timeout by default
rbhive
RBHive.tcli_connect(host, port, timeout: 1) do |connection|
# ...
end
Raises Thrift::TransportException
reversed
Reversed.lookup("8.8.8.8", timeout: 1)
Returns nil on timeouts
savon
Savon.client(wsdl: url, open_timeout: 1, read_timeout: 1)
Raises
HTTPClient::ConnectTimeoutErroron connect timeoutHTTPClient::ReceiveTimeoutErroron read timeout
spydr
Spidr.open_timeout = 1
Spidr.read_timeout = 1
No exception is raised. Check for failures with
agent = Spidr.site(url)
agent.failures
spyke
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
Stomp::Client.new(start_timeout: 1, connect_timeout: 1, connread_timeout: 1, parse_timeout: 1)
Raises
Stomp::Error::StartTimeoutExceptionon connect timeoutStomp::Error::ReceiveTimeouton read timeout
thrift
Thrift::Socket.new(host, port, 1)
Raises Thrift::TransportException
thrift_client
ThriftClient.new(client_class, servers, connect_timeout: 1, timeout: 1)
Raises
ThriftClient::NoServersAvailableon connect timeout- TODO: read timeout
vault
Vault.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
Whois::Client.new(timeout: 1)
Default: 10s
Raises Timeout::Error
zk
Not configurable at the moment
Default: 30s
Raises Zookeeper::Exceptions::ContinuationTimeoutError
zookeeper
Not configurable at the moment
Default: 30s
Raises Zookeeper::Exceptions::ContinuationTimeoutError
Don’t see a library you use?
Let us know. Even better, create a pull request for it.
Rescuing Exceptions
Take advantage of inheritance. Instead of
rescue Net::OpenTimeout, Net::ReadTimeout
you can do
rescue Timeout::Error
Use
Timeout::Errorfor bothNet::OpenTimeoutandNet::ReadTimeoutFaraday::ClientErrorfor bothFaraday::ConnectionFailedandFaraday::TimeoutErrorHTTPClient::TimeoutErrorfor bothHTTPClient::ConnectTimeoutErrorandHTTPClient::ReceiveTimeoutErrorRedis::BaseConnectionErrorfor bothRedis::CannotConnectErrorandRedis::TimeoutErrorRack::Timeout::Errorfor bothRack::Timeout::RequestTimeoutErrorandRack::Timeout::RequestExpiryErrorRestClient::Exceptions::Timeoutfor bothRestClient::Exceptions::OpenTimeoutandRestClient::Exceptions::ReadTimeout
Existing Services
Adding timeouts to existing services can be a daunting task, but there’s a low risk way to do it.
- Select a timeout - say 5 seconds
- Log instances exceeding the proposed timeout
- Fix them
- Add the timeout
- Repeat this process with a lower timeout, until your target timeout is achieved
Running the Tests
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:
- Add it to
Appraisalsand runbundle exec appraisal generate - Run
bundle exec appraisal new_gem bundle - Create
test/new_gem_test.rband runbundle exec appraisal new_gem rake test - Add it to the appropriate section of the readme
And lastly...
Because time is not going to go backwards, I think I better stop now. - Stephen Hawking
:clock4: