[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7964":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":15,"stars30d":16,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":19,"hasPages":19,"topics":21,"createdAt":10,"pushedAt":10,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":15,"starSnapshotCount":15,"syncStatus":25,"lastSyncTime":26,"discoverSource":27},7964,"the-ultimate-guide-to-ruby-timeouts","ankane\u002Fthe-ultimate-guide-to-ruby-timeouts","ankane","Timeouts for popular Ruby gems","",null,"Ruby",2493,100,40,0,3,58.31,"MIT License",false,"master",[],"2026-06-12 04:00:36","# The Ultimate Guide to Ruby Timeouts\n\nAn 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.**\n\nHere’s how to add timeouts for popular Ruby gems. **[All have been tested](test)**. You should [avoid Ruby’s `Timeout` module](https:\u002F\u002Fwww.mikeperham.com\u002F2015\u002F05\u002F08\u002Ftimeout-rubys-most-dangerous-api\u002F). The default is no timeout, unless otherwise specified. Enjoy!\n\nAlso available for [Python](https:\u002F\u002Fgithub.com\u002Fankane\u002Fpython-timeouts), [Node](https:\u002F\u002Fgithub.com\u002Fankane\u002Fnode-timeouts), [Go](https:\u002F\u002Fgithub.com\u002Fankane\u002Fgo-timeouts), [PHP](https:\u002F\u002Fgithub.com\u002Fankane\u002Fphp-timeouts), and [Rust](https:\u002F\u002Fgithub.com\u002Fankane\u002Frust-timeouts)\n\n[![Build Status](https:\u002F\u002Fgithub.com\u002Fankane\u002Fthe-ultimate-guide-to-ruby-timeouts\u002Factions\u002Fworkflows\u002Fbuild.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fankane\u002Fthe-ultimate-guide-to-ruby-timeouts\u002Factions)\n\n## Timeout Types\n\n- **connect (or open)** - time to open the connection\n- **read (or receive)** - time to receive data after connected\n- **write (or send)** - time to send data after connected\n- **checkout** - time to checkout a connection from the pool\n- **statement** - time to execute a database statement\n- **lock (or acquisition)** - time to acquire a lock\n- **request (or service)** - time to process a request\n- **wait** - time to start processing a queued request\n- **command** - time to run a command\n- **solve** - time to solve an optimization problem\n\n## Statement Timeouts\n\nFor many apps, the *single most important thing* to do (if you use a relational database)\n\n- [PostgreSQL](#postgresql)\n- [MySQL](#mysql)\n- [MariaDB](#mariadb)\n\n## Gems\n\nStandard Library\n\n- [io](#io)\n- [net\u002Fftp](#netftp)\n- [net\u002Fhttp](#nethttp)\n- [net\u002Fimap](#netimap)\n- [net\u002Fpop](#netpop)\n- [net\u002Fsmtp](#netsmtp)\n- [open-uri](#open-uri)\n- [regexp](#regexp)\n- [socket](#socket)\n\nData Stores\n\n- [activerecord](#activerecord)\n- [bunny](#bunny)\n- [cassandra-driver](#cassandra-driver)\n- [connection_pool](#connection_pool)\n- [couchrest](#couchrest)\n- [dalli](#dalli)\n- [drill-sergeant](#drill-sergeant)\n- [elasticsearch](#elasticsearch)\n- [hiredis](#hiredis)\n- [immudb](#immudb)\n- [influxdb](#influxdb)\n- [influxdb-client](#influxdb-client)\n- [meilisearch](#meilisearch)\n- [mongo](#mongo)\n- [mongoid](#mongoid)\n- [mysql2](#mysql2)\n- [neo4j](#neo4j)\n- [pg](#pg)\n- [presto-client](#presto-client)\n- [redis](#redis)\n- [redis-client](#redis-client)\n- [riddle](#riddle)\n- [rsolr](#rsolr)\n- [ruby-druid](#ruby-druid)\n- [ruby-kafka](#ruby-kafka)\n- [searchkick](#searchkick)\n- [sequel](#sequel)\n- [trino-client](#trino-client)\n- [typesense](#typesense)\n\nHTTP Clients\n\n- [curb](#curb)\n- [down](#down)\n- [em-http-client](#em-http-client)\n- [excon](#excon)\n- [faraday](#faraday)\n- [http](#http)\n- [httparty](#httparty)\n- [httpclient](#httpclient)\n- [httpi](#httpi)\n- [patron](#patron)\n- [rest-client](#rest-client)\n- [typhoeus](#typhoeus)\n\nCommands\n\n- [mixlib-shellout](#mixlib-shellout)\n- [posix-spawn](#posix-spawn)\n- [tty-command](#tty-command)\n\nWeb Servers\n\n- [puma](#puma)\n- [unicorn](#unicorn)\n\nRack Middleware\n\n- [rack-timeout](#rack-timeout)\n- [slowpoke](#slowpoke)\n\nSolvers\n\n- [or-tools](#or-tools)\n- [osqp](#osqp)\n- [ruby-cbc](#ruby-cbc)\n- [scs](#scs)\n\nDistributed Locks\n\n- [activerecord](#activerecord-1)\n- [mlanett-redis-lock](#mlanett-redis-lock)\n- [redlock](#redlock)\n- [suo](#suo)\n- [with_advisory_lock](#with_advisory_lock)\n\n3rd Party Services\n\n- [airrecord](#airrecord)\n- [airtable](#airtable)\n- [algoliasearch](#algoliasearch)\n- [aws-sdk](#aws-sdk)\n- [azure](#azure)\n- [bitly](#bitly)\n- [boxr](#boxr)\n- [checkr-official](#checkr-official)\n- [clearbit](#clearbit)\n- [dogapi](#dogapi)\n- [dropbox-sdk](#dropbox-sdk)\n- [droplet_kit](#droplet_kit)\n- [fastly](#fastly)\n- [firebase](#firebase)\n- [flickraw](#flickraw)\n- [gibbon](#gibbon)\n- [github_api](#github_api)\n- [gitlab](#gitlab)\n- [google-api-client](#google-api-client)\n- [google-cloud](#google-cloud)\n- [intercom](#intercom)\n- [jira-ruby](#jira-ruby)\n- [koala](#koala)\n- [linkedin](#linkedin)\n- [octokit](#octokit)\n- [pusher](#pusher)\n- [pwned](#pwned)\n- [restforce](#restforce)\n- [rspotify](#rspotify)\n- [ruby-trello](#ruby-trello)\n- [sentry-ruby](#sentry-ruby)\n- [shopify_api](#shopify_api)\n- [sift](#sift)\n- [slack-notifier](#slack-notifier)\n- [slack-ruby-client](#slack-ruby-client)\n- [smartystreets_ruby_sdk](#smartystreets_ruby_sdk)\n- [soda-ruby](#soda-ruby)\n- [soundcloud](#soundcloud)\n- [stripe](#stripe)\n- [tamber](#tamber)\n- [twilio-ruby](#twilio-ruby)\n- [twitter](#twitter)\n- [yt](#yt)\n- [zendesk_api](#zendesk_api)\n\nOther\n\n- [acme-client](#acme-client)\n- [actionmailer](#actionmailer)\n- [activemerchant](#activemerchant)\n- [activeresource](#activeresource)\n- [carrot2](#carrot2)\n- [docker-api](#docker-api)\n- [etcd](#etcd)\n- [etcdv3](#etcdv3)\n- [fastimage](#fastimage)\n- [geocoder](#geocoder)\n- [graphql-client](#graphql-client)\n- [grpc](#grpc)\n- [hexspace](#hexspace)\n- [ignite-client](#ignite-client)\n- [kubeclient](#kubeclient)\n- [mail](#mail)\n- [mechanize](#mechanize)\n- [nats-pure](#nats-pure)\n- [nestful](#nestful)\n- [net-dns](#net-dns)\n- [net-ldap](#net-ldap)\n- [net-ntp](#net-ntp)\n- [net-scp](#net-scp)\n- [net-sftp](#net-sftp)\n- [net-ssh](#net-ssh)\n- [net-telnet](#net-telnet)\n- [omniauth-oauth2](#omniauth-oauth2)\n- [rbhive](#rbhive)\n- [reversed](#reversed)\n- [savon](#savon)\n- [spidr](#spidr)\n- [spyke](#spyke)\n- [stomp](#stomp)\n- [thrift](#thrift)\n- [thrift_client](#thrift_client)\n- [vault](#vault)\n- [whois](#whois)\n- [zk](#zk)\n- [zookeeper](#zookeeper)\n\n## Statement Timeouts\n\nPrevent single queries from taking up all of your database’s resources.\n\n### PostgreSQL\n\nIf you use Rails, add to your `config\u002Fdatabase.yml`\n\n```yml\nproduction:\n  variables:\n    statement_timeout: 5s # or ms, min, etc\n```\n\nor set it on your database role\n\n```sql\nALTER ROLE myuser SET statement_timeout = '5s';\n```\n\nTest with\n\n```sql\nSELECT pg_sleep(6);\n```\n\nTo set for a single transaction, use\n\n```sql\nBEGIN;\nSET LOCAL statement_timeout = '5s';\n...\nCOMMIT;\n```\n\nFor migrations, you likely want to set a longer statement timeout. You can do this with\n\n```yml\nproduction:\n  variables:\n    statement_timeout: \u003C%= ENV[\"STATEMENT_TIMEOUT\"] || \"5s\" %>\n```\n\nAnd use\n\n```sh\nSTATEMENT_TIMEOUT=90s rails db:migrate\n```\n\n### MySQL\n\n**Note:** Only applies to read-only `SELECT` statements ([more info](https:\u002F\u002Fdev.mysql.com\u002Fdoc\u002Frefman\u002F8.4\u002Fen\u002Fserver-system-variables.html#sysvar_max_execution_time))\n\nIf you use Rails, add to your `config\u002Fdatabase.yml`\n\n```yml\nproduction:\n  variables:\n    max_execution_time: 5000 # ms\n```\n\nor set it directly on each connection\n\n```sql\nSET SESSION max_execution_time = 5000;\n```\n\nTest with\n\n```sql\nSELECT 1 FROM information_schema.tables WHERE sleep(6);\n```\n\nTo set for a single statement, use an [optimizer hint](https:\u002F\u002Fdev.mysql.com\u002Fdoc\u002Frefman\u002F5.7\u002Fen\u002Foptimizer-hints.html#optimizer-hints-execution-time)\n\n```sql\nSELECT \u002F*+ MAX_EXECUTION_TIME(5000) *\u002F ...\n```\n\n### MariaDB\n\nIf you use Rails, add to your `config\u002Fdatabase.yml`\n\n```yml\nproduction:\n  variables:\n    max_statement_time: 5 # sec\n```\n\nor set it directly on each connection\n\n```sql\nSET SESSION max_statement_time = 5;\n```\n\nTest with\n\n```sql\nSELECT 1 FROM information_schema.tables WHERE sleep(6);\n```\n\nTo set for a single statement, use\n\n```sql\nSET STATEMENT max_statement_time=5 FOR\n  SELECT ...\n```\n\nFor migrations, you likely want to set a longer statement timeout. You can do this with\n\n```yml\nproduction:\n  variables:\n    max_statement_time: \u003C%= ENV['MAX_STATEMENT_TIME'] || 5 %>\n```\n\nAnd use\n\n```sh\nMAX_STATEMENT_TIME=90 rails db:migrate\n```\n\n[Official docs](https:\u002F\u002Fmariadb.com\u002Fkb\u002Fen\u002Fmariadb\u002Faborting-statements\u002F)\n\n## Standard Library\n\n### io\n\n**Note:** Requires Ruby 3.2+\n\n```ruby\nSTDIN.timeout = 1\n```\n\nRaises `IO::TimeoutError`\n\n### net\u002Fftp\n\n```ruby\nNet::FTP.new(host, open_timeout: 1, read_timeout: 1)\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### net\u002Fhttp\n\n```ruby\nNet::HTTP.start(host, port, open_timeout: 1, read_timeout: 1, write_timeout: 1) do\n  # ...\nend\n```\n\nor\n\n```ruby\nhttp = Net::HTTP.new(host, port)\nhttp.open_timeout = 1\nhttp.read_timeout = 1\nhttp.write_timeout = 1\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n- `Net::WriteTimeout` on write timeout\n\nDefault: 60s connect timeout, 60s read timeout, 60s write timeout\n\nRead timeouts are retried once automatically for idempotent methods like `GET`. You can set the max number of retries with `http.max_retries = 1`.\n\n### net\u002Fimap\n\n```ruby\nNet::IMAP.new(host, open_timeout: 1)\n```\n\nRead timeout is not configurable at the moment\n\nRaises `Net::OpenTimeout` on connect timeout\n\n### net\u002Fpop\n\n```ruby\npop = Net::POP.new(host)\npop.open_timeout = 1\npop.read_timeout = 1\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### net\u002Fsmtp\n\n```ruby\nsmtp = Net::SMTP.new(host, 25)\nsmtp.open_timeout = 1\nsmtp.read_timeout = 1\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### open-uri\n\n```ruby\nURI.parse(url).open(open_timeout: 1, read_timeout: 1)\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### regexp\n\n**Note:** Requires Ruby 3.2+\n\n```ruby\nRegexp.timeout = 1\n# or\nRegexp.new(regexp, timeout: 1)\n```\n\nRaises `Regexp::TimeoutError`\n\n### socket\n\n```ruby\nSocket.tcp(host, 80, connect_timeout: 1) do |sock|\n  # ...\nend\n```\n\nRaises `Errno::ETIMEDOUT`\n\n## Data Stores\n\n### activerecord\n\n- #### postgres adapter\n\n  ```ruby\n  ActiveRecord::Base.establish_connection(connect_timeout: 1, checkout_timeout: 1, ...)\n  ```\n\n  or in `config\u002Fdatabase.yml`\n\n  ```yaml\n  production:\n    connect_timeout: 1\n    checkout_timeout: 1\n  ```\n\n  Raises\n\n  - `ActiveRecord::ConnectionNotEstablished` on connect and read timeouts\n  - `ActiveRecord::ConnectionTimeoutError` on checkout timeout\n\n  See also [PostgreSQL statement timeouts](#postgresql)\n\n- #### mysql2 adapter\n\n  ```ruby\n  ActiveRecord::Base.establish_connection(connect_timeout: 1, read_timeout: 1, write_timeout: 1, checkout_timeout: 1, ...)\n  ```\n\n  or in `config\u002Fdatabase.yml`\n\n  ```yaml\n  production:\n    connect_timeout: 1\n    read_timeout: 1\n    write_timeout: 1\n    checkout_timeout: 1\n  ```\n\n  Raises\n\n  - `ActiveRecord::ConnectionNotEstablished` on connect and read timeouts\n  - `ActiveRecord::ConnectionTimeoutError` on checkout timeout\n\n  See also [MySQL statement timeouts](#mysql)\n\n### bunny\n\n```ruby\nBunny.new(connection_timeout: 1, read_timeout: 1, ...)\n```\n\nRaises\n\n- `Bunny::TCPConnectionFailedForAllHosts` on connect timeout\n- `Bunny::NetworkFailure` on read timeout\n\n### cassandra-driver\n\n```ruby\nCassandra.cluster(connect_timeout: 1, timeout: 1)\n```\n\nDefault: 10s connect timeout, 12s read timeout\n\nRaises\n\n- `Cassandra::Errors::NoHostsAvailable` on connect timeout\n- `Cassandra::Errors::TimeoutError` on read timeout\n\n### connection_pool\n\n```ruby\nConnectionPool.new(timeout: 1) { ... }\n```\n\nRaises `ConnectionPool::TimeoutError`\n\n### couchrest\n\n```ruby\nCouchRest.new(url, open_timeout: 1, read_timeout: 1, timeout: 1)\n```\n\nRaises\n\n- `HTTPClient::ConnectTimeoutError` on connect timeout\n- `HTTPClient::ReceiveTimeoutError` on read timeout\n\n### dalli\n\n```ruby\nDalli::Client.new(host, socket_timeout: 1, ...)\n```\n\nDefault: 1s\n\nRaises `Dalli::RingError`\n\n### drill-sergeant\n\n```ruby\nDrill.new(url: url, open_timeout: 1, read_timeout: 1)\n```\n\nDefault: 3s connect timeout, no read timeout\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### elasticsearch\n\n```ruby\nElasticsearch::Client.new(transport_options: {request: {timeout: 1}}, ...)\n```\n\nRaises `Elastic::Transport::Transport::Error`\n\n### hiredis\n\n```ruby\nconn = Hiredis::Connection.new\nconn.timeout = 1_000_000 # microseconds\n```\n\nRaises\n\n- `Errno::ETIMEDOUT` on connect timeout\n- `Errno::EAGAIN` on read timeout\n\n### immudb\n\n```ruby\nImmudb::Client.new(host, timeout: 1)\n```\n\nRaises `GRPC::DeadlineExceeded`\n\n### influxdb\n\n```ruby\nInfluxDB::Client.new(open_timeout: 1, read_timeout: 1)\n```\n\nRaises `InfluxDB::ConnectionError`\n\n### influxdb-client\n\n```ruby\nInfluxDB2::Client.new(url, token, open_timeout: 1, read_timeout: 1)\n```\n\nRaises `InfluxDB2::InfluxError`\n\n### meilisearch\n\n```ruby\nMeilisearch::Client.new(url, api_key, timeout: 1)\n```\n\nRaises `Meilisearch::TimeoutError`\n\n### mongo\n\n```ruby\nMongo::Client.new([host], connect_timeout: 1, socket_timeout: 1, server_selection_timeout: 1, ...)\n```\n\nRaises `Mongo::Error::NoServerAvailable`\n\n### mongoid\n\n```yml\nproduction:\n  clients:\n    default:\n      options:\n        connect_timeout: 1\n        socket_timeout: 1\n        server_selection_timeout: 1\n```\n\nRaises `Mongo::Error::NoServerAvailable`\n\n### mysql2\n\n```ruby\nMysql2::Client.new(connect_timeout: 1, read_timeout: 1, write_timeout: 1, ...)\n```\n\nRaises `Mysql2::Error`\n\n### neo4j\n\n```ruby\nconfig.neo4j.session.options = {\n  faraday_configurator: lambda do |faraday|\n    faraday.adapter :typhoeus\n    faraday.options[:open_timeout] = 5\n    faraday.options[:timeout] = 65\n  end\n}\n```\n\nRaises `Faraday::TimeoutError`\n\n### pg\n\n```ruby\nPG.connect(connect_timeout: 1, ...)\n```\n\nRaises `PG::ConnectionBad`\n\n### presto-client\n\n```ruby\nPresto::Client.new(http_open_timeout: 1, http_timeout: 1)\n```\n\nRaises\n\n- `Faraday::ConnectionFailed` on connect timeout\n- `Faraday::TimeoutError` on read timeout\n\n### redis\n\n```ruby\nRedis.new(connect_timeout: 1, timeout: 1, ...)\n```\n\nDefault: 1s after 5.0, 5s before\n\nRaises\n\n- `Redis::CannotConnectError` on connect timeout\n- `Redis::TimeoutError` on read timeout\n\n### redis-client\n\n```ruby\nRedisClient.config(timeout: 1, ...)\n# or\nRedisClient.config(connect_timeout: 1, read_timeout: 1, write_timeout: 1, ...)\n```\n\nDefault: 1s\n\nRaises `RedisClient::CannotConnectError`\n\n### riddle\n\n```ruby\nclient = Riddle::Client.new\nclient.timeout = 1\n```\n\nRaises `Riddle::ResponseError`\n\n### rsolr\n\n```ruby\nRSolr.connect(open_timeout: 1, timeout: 1)\n```\n\nRaises\n\n- `RSolr::Error::ConnectionRefused` on connect timeout\n- `RSolr::Error::Timeout` on read timeout\n\n### ruby-druid\n\nNot configurable at the moment\n\nDefault: 10s connect timeout, no read timeout\n\n### ruby-kafka\n\n```ruby\nKafka.new(connect_timeout: 1, socket_timeout: 1)\n```\n\nRaises `Kafka::ConnectionError`\n\n### searchkick\n\n```ruby\nSearchkick.timeout = 1\nSearchkick.search_timeout = 1\n```\n\nDefault: 10s\n\nRaises same exceptions as [elasticsearch](#elasticsearch)\n\n### sequel\n\n- #### postgres adapter\n\n  ```ruby\n  Sequel.connect(connect_timeout: 1, pool_timeout: 1, ...)\n  ```\n\n  Raises\n\n  - `Sequel::DatabaseConnectionError` on connect and read timeouts\n  - `Sequel::PoolTimeout` on checkout timeout\n\n- #### mysql2 adapter\n\n  ```ruby\n  Sequel.connect(timeout: 1, read_timeout: 1, connect_timeout: 1, pool_timeout: 1, ...)\n  ```\n\n  Raises\n\n  - `Sequel::DatabaseConnectionError` on connect and read timeouts\n  - `Sequel::PoolTimeout` on checkout timeout\n\n### trino-client\n\n```ruby\nTrino::Client.new(http_open_timeout: 1, http_timeout: 1)\n```\n\nRaises\n\n- `Faraday::ConnectionFailed` on connect timeout\n- `Faraday::TimeoutError` on read timeout\n\n### typesense\n\n```ruby\nTypesense::Client.new(connection_timeout_seconds: 1)\n```\n\nRaises\n\n- `Faraday::ConnectionFailed` on connect timeout\n- `Faraday::TimeoutError` on read timeout\n\n## HTTP Clients\n\n### curb\n\n```ruby\ncurl = Curl::Easy.new(url)\ncurl.connect_timeout = 1\ncurl.timeout = 1\ncurl.perform\n```\n\nRaises `Curl::Err::TimeoutError`\n\n### down\n\n```ruby\nDown::NetHttp.download(connect_url, open_timeout: 1, read_timeout: 1)\n```\n\nRaises `Down::TimeoutError`\n\n### em-http-client\n\n```ruby\nEventMachine.run do\n  http = EventMachine::HttpRequest.new(url, connect_timeout: 1, inactivity_timeout: 1).get\n  http.errback  { http.error }\nend\n```\n\nNo exception is raised, but `http.error` is set to `Errno::ETIMEDOUT` in `http.errback`.\n\n### excon\n\n```ruby\nExcon.get(url, connect_timeout: 1, read_timeout: 1, write_timeout: 1)\n```\n\nRaises `Excon::Errors::Timeout`\n\n### faraday\n\n```ruby\nFaraday.get(url) do |req|\n  req.options.open_timeout = 1\n  req.options.timeout = 1\nend\n```\n\nor\n\n```ruby\nFaraday.new(url, request: {open_timeout: 1, timeout: 1}) do |faraday|\n  # ...\nend\n```\n\nRaises\n\n- `Faraday::ConnectionFailed` on connect timeout\n- `Faraday::TimeoutError` on read timeout\n\n### http\n\n```ruby\nHTTP.timeout(connect: 1, read: 1, write: 1).get(url)\n```\n\nRaises\n\n- `HTTP::ConnectTimeoutError` on connect timeout\n- `HTTP::TimeoutError` on read timeout\n\n### httparty\n\n```ruby\nHTTParty.get(url, timeout: 1)\n```\n\nor\n\n```ruby\nclass Resource\n  include HTTParty\n\n  default_timeout 1\n  # or\n  open_timeout 1\n  read_timeout 1\n  write_timeout 1\nend\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### httpclient\n\n```ruby\nclient = HTTPClient.new\nclient.connect_timeout = 1\nclient.receive_timeout = 1\nclient.send_timeout = 1\nclient.get(url)\n```\n\nRaises\n\n- `HTTPClient::ConnectTimeoutError` on connect timeout\n- `HTTPClient::ReceiveTimeoutError` on read timeout\n\n### httpi\n\n```ruby\nHTTPI::Request.new(url: url, open_timeout: 1)\n```\n\nRaises same errors as underlying client\n\n### patron\n\n```ruby\nsess = Patron::Session.new\nsess.connect_timeout = 1\nsess.timeout = 1\n```\n\nRaises `Patron::TimeoutError`\n\n### rest-client\n\n```ruby\nRestClient::Request.execute(method: :get, url: url, open_timeout: 1, read_timeout: 1)\n\n# shorthand to set open_timeout = read_timeout = 1\nRestClient::Request.execute(method: :get, url: url, timeout: 1)\n```\n\nSame options also work with `RestClient::Resource`.\n\nRaises\n\n- `RestClient::Exceptions::OpenTimeout` on connect timeout\n- `RestClient::Exceptions::ReadTimeout` on read timeout\n\nDefault: 60s connect timeout, 60s read timeout\n\n### typhoeus\n\n```ruby\nresponse = Typhoeus.get(url, connecttimeout: 1, timeout: 1)\n```\n\nNo exception is raised. Check for a timeout with\n\n```ruby\nresponse.timed_out?\n```\n\n## Commands\n\n### mixlib-shellout\n\n```ruby\nMixlib::ShellOut.new(command, timeout: 1)\n```\n\nRaises `Mixlib::ShellOut::CommandTimeout`\n\n### posix-spawn\n\n```ruby\nPOSIX::Spawn::Child.new(command, timeout: 1)\n```\n\nRaises `POSIX::Spawn::TimeoutExceeded`\n\n### tty-command\n\n```ruby\nTTY::Command.new(timeout: 1)\n```\n\nor\n\n```ruby\ncmd.run(command, timeout: 1)\n```\n\nRaises `TTY::Command::TimeoutExceeded`\n\n## Web Servers\n\n### puma\n\n```ruby\n# config\u002Fpuma.rb\nworker_timeout 15\n```\n\nDefault: 60s\n\nThis kills and respawns the worker process. Note that this is for the worker and not threads. This isn’t a [request timeout](https:\u002F\u002Fgithub.com\u002Fpuma\u002Fpuma\u002Fissues\u002F160) either. Use [Rack middleware](#rack-middleware) for request timeouts.\n\n```ruby\n# config\u002Fpuma.rb\nworker_shutdown_timeout 8\n```\n\nDefault: 30s\n\nThis 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.\n\n### unicorn\n\n```ruby\n# config\u002Funicorn.rb\ntimeout 15\n```\n\nDefault: 60s\n\nThis kills and respawns the worker process.\n\nIt’s recommended to use this in addition to [Rack middleware](#rack-middleware).\n\n## Rack Middleware\n\n### rack-timeout\n\n```ruby\nuse Rack::Timeout,\n  service_timeout:   15,     # ENV[\"RACK_TIMEOUT_SERVICE_TIMEOUT\"]\n  wait_timeout:      30,     # ENV[\"RACK_TIMEOUT_WAIT_TIMEOUT\"]\n  wait_overtime:     60,     # ENV[\"RACK_TIMEOUT_WAIT_OVERTIME\"]\n  service_past_wait: false,  # ENV[\"RACK_TIMEOUT_SERVICE_PAST_WAIT\"]\n  term_on_timeout:   false   # ENV[\"RACK_TIMEOUT_TERM_ON_TIMEOUT\"]\n```\n\nDefault: 15s service timeout, 30s wait timeout\n\nRaises `Rack::Timeout::RequestTimeoutError` or `Rack::Timeout::RequestExpiryError`\n\n[Read more here](https:\u002F\u002Fgithub.com\u002Fheroku\u002Frack-timeout\u002Fblob\u002Fmaster\u002Fdoc\u002Fsettings.md)\n\n**Note:** The approach used by Rack::Timeout can leave your application in an inconsistent state, [as described here](https:\u002F\u002Fgithub.com\u002Fheroku\u002Frack-timeout\u002Fblob\u002Fmaster\u002Fdoc\u002Frisks.md). You can use [term on timeout](https:\u002F\u002Fgithub.com\u002Fsharpstone\u002Frack-timeout\u002Fblob\u002Fmaster\u002Fdoc\u002Fsettings.md#term-on-timeout) to avoid this.\n\n### slowpoke\n\n```ruby\nSlowpoke.timeout = 5\n```\n\nDefault: 15s\n\nRaises same exceptions as [rack-timeout](#rack-timeout)\n\n## Solvers\n\n### or-tools\n\n```ruby\nrouting.solve(time_limit: 1)\n```\n\n### osqp\n\n```ruby\nsolver.solve(p, q, a, l, u, time_limit: 1)\n```\n\nCheck for a `status` of `run time limit reached` for a timeout\n\n### ruby-cbc\n\n```ruby\nproblem.set_time_limit(1)\n```\n\nor\n\n```ruby\nproblem.solve(sec: 1)\n```\n\nCheck for a timeout with\n\n```ruby\nproblem.time_limit_reached?\n```\n\n### scs\n\n```ruby\nsolver.solve(data, cone, time_limit_secs: 1)\n```\n\nCheck for a `status` of `solved (inaccurate - reached time_limit_secs)` for a timeout\n\n## Distributed Locks\n\n### activerecord\n\n```ruby\nActiveRecord::Base.connection.get_advisory_lock(123)\n```\n\nReturns `false` if lock cannot be immediately acquired\n\n### mlanett-redis-lock\n\n```ruby\nredis.lock(key, life: 1, acquire: 1) do |lock|\n  # ...\nend\n```\n\nDefault: 10s acquisition timeout\n\nRaises `Redis::Lock::LockNotAcquired`\n\n### redlock\n\n```ruby\nlock_manager.lock!(key, 1000) do\n  # ...\nend\n```\n\nDefault: 200ms acquisition timeout with 3 retries\n\nRaises `Redlock::LockError`\n\n### suo\n\n```ruby\nSuo::Client::Memcached.new(key, acquisition_timeout: 1)\n```\n\nor\n\n```ruby\nSuo::Client::Redis.new(key, acquisition_timeout: 1)\n```\n\nDefault: 0.1s acquisition timeout with 10 retries\n\nThe `lock` method returns `nil` on timeout\n\n### with_advisory_lock\n\n```ruby\nActiveRecord::Base.with_advisory_lock(\"123\", timeout_seconds: 1) do\n  # ...\nend\n```\n\nReturns `false` on acquisition timeout\n\n## 3rd Party Services\n\n### airrecord\n\nNot configurable at the moment, and no timeout by default\n\n### airtable\n\n```ruby\nAirtable::Resource.default_timeout 1\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### algoliasearch\n\n```ruby\nAlgolia.init(\n  connect_timeout: 1,\n  send_timeout: 1,\n  receive_timeout: 1,\n  batch_timeout: 1,\n  search_timeout: 1\n)\n```\n\nRaises `Algolia::AlgoliaProtocolError`\n\n### aws-sdk\n\n```ruby\nAws.config = {\n  http_open_timeout: 1,\n  http_read_timeout: 1\n}\n```\n\nOr with a client\n\n```ruby\nAws::S3::Client.new(\n  http_open_timeout: 1,\n  http_read_timeout: 1\n)\n```\n\nRaises `Seahorse::Client::NetworkingError`\n\n### azure\n\nNot configurable at the moment, and no timeout by default\n\n### bitly\n\n```ruby\nadapter = Bitly::HTTP::Adapters::NetHTTP.new(request_opts: {\n  open_timeout: 1,\n  read_timeout: 1\n})\nhttp_client = Bitly::HTTP::Client.new(adapter)\nclient = Bitly::API::Client.new(token: token, http: http_client)\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### boxr\n\n```ruby\nBoxr::BOX_CLIENT.connect_timeout = 1\nBoxr::BOX_CLIENT.receive_timeout = 1\nBoxr::BOX_CLIENT.send_timeout = 1\n```\n\nRaises\n\n- `HTTPClient::ConnectTimeoutError` on connect timeout\n- `HTTPClient::ReceiveTimeoutError` on read timeout\n\n### checkr-official\n\nDefault: 30s connect timeout, 60s read timeout\n\nNot configurable at the moment\n\n### clearbit\n\n```ruby\nClearbit::Resource.options = {timeout: 1}\n```\n\nRaises `Nestful::TimeoutError`\n\n### dogapi\n\n```ruby\ntimeout = 1\nDogapi::Client.new(api_key, nil, nil, nil, false, timeout)\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### dropbox-sdk\n\nNot configurable at the moment\n\nDefault: No connect timeout, 600s read timeout\n\n### droplet_kit\n\n```ruby\nDropletKit::Client.new(open_timeout: 1, timeout: 1)\n```\n\nRaises\n\n- `Faraday::ConnectionFailed` on connect timeout\n- `Faraday::TimeoutError` on read timeout\n\n### fastly\n\nNot configurable at the moment, and no timeout by default\n\n### firebase\n\n```ruby\nfirebase = Firebase::Client.new(url)\nfirebase.request.connect_timeout = 1\nfirebase.request.receive_timeout = 1\nfirebase.request.send_timeout = 1\n```\n\nRaises\n\n- `HTTPClient::ConnectTimeoutError` on connect timeout\n- `HTTPClient::ReceiveTimeoutError` on read timeout\n\n### flickraw\n\nNot configurable at the moment\n\n### gibbon\n\n```ruby\nGibbon::Request.new(open_timeout: 1, timeout: 1, ...)\n```\n\nRaises `Gibbon::MailChimpError`\n\n### github_api\n\n```ruby\nGithub.new(connection_options: {request: {open_timeout: 1, timeout: 1}})\n```\n\nRaises\n\n- `Faraday::ConnectionFailed` on connect timeout\n- `Faraday::TimeoutError` on read timeout\n\n### gitlab\n\n```ruby\nGitlab.client(httparty: {timeout: 1})\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### google-api-client\n\n```ruby\nclient = Google::Apis::DriveV2::DriveService.new\nclient.client_options.open_timeout_sec = 1\nclient.client_options.read_timeout_sec = 1\n```\n\nRaise `Google::Apis::TransmissionError`\n\n### google-cloud\n\n```ruby\nGoogle::Cloud::Storage.new(timeout: 1)\n```\n\nRaises `Google::Cloud::Error`\n\n### intercom\n\n```ruby\nclient = Intercom::Client.new(token: token)\nclient.options(Intercom::Client.set_timeouts(open_timeout: 1, read_timeout: 1))\n```\n\nRaises\n\n- `Intercom::ServiceConnectionError` on connect timeout (inherits from `Intercom::IntercomError`)\n- `Intercom::ServiceUnavailableError` on read timeout (inherits from `Intercom::IntercomError`)\n\n### jira-ruby\n\n```ruby\nJIRA::Client.new(read_timeout: 1)\n```\n\nConnect timeout is not configurable at the moment\n\nRaises `Net::ReadTimeout` on read timeout\n\n### koala\n\n```ruby\nKoala.http_service.http_options = {request: {open_timeout: 1, timeout: 1}}\n```\n\nRaises `Faraday::ConnectionFailed`\n\n### linkedin\n\nNot configurable at the moment, and no timeout by default.\n\n### octokit\n\n```ruby\nOctokit::Client.new(connection_options: {request: {open_timeout: 1, timeout: 1}})\n```\n\nRaises\n\n- `Faraday::ConnectionFailed` on connect timeout\n- `Faraday::TimeoutError` on read timeout\n\n### pusher\n\n```ruby\nclient.timeout = 1\n# or\nclient.connect_timeout = 1\nclient.send_timeout = 1\nclient.receive_timeout = 1\nclient.keep_alive_timeout = 1\n```\n\nRaises `Pusher::HTTPError`\n\n### pwned\n\n```ruby\nPwned::Password.new(\"password\", open_timeout: 1, read_timeout: 1)\n```\n\nRaises `Pwned::TimeoutError`\n\n### restforce\n\n```ruby\nRestforce.new(timeout: 1)\n```\n\nRaises\n\n- `Faraday::ConnectionFailed` on connect timeout\n- `Faraday::TimeoutError` on read timeout\n\n### rspotify\n\nNot configurable at the moment, and no timeout by default\n\n### ruby-trello\n\nNot configurable at the moment, and no timeout by default\n\n### sentry-ruby\n\n```ruby\nSentry.init do |config|\n  config.transport.open_timeout = 1\n  config.transport.timeout = 1\nend\n```\n\nDefault: 1s connect timeout, 2s read\u002Fwrite timeout\n\nRaises `Sentry::ExternalError` in [some cases](https:\u002F\u002Fgithub.com\u002Fgetsentry\u002Fsentry-ruby\u002Fissues\u002F1290)\n\n### shopify_api\n\nNot configurable at the moment, and no timeout by default\n\n### sift\n\n```ruby\nSift::Client.new(timeout: 1)\n```\n\nDefault: 2s\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### slack-notifier\n\n```ruby\nSlack::Notifier.new(webhook_url, http_options: {open_timeout: 1, read_timeout: 1})\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### slack-ruby-client\n\n```ruby\nSlack::Web::Client.new(open_timeout: 1, timeout: 1)\n```\n\nRaises `Slack::Web::Api::Errors::TimeoutError`\n\n### smartystreets_ruby_sdk\n\n```ruby\nSmartyStreets::ClientBuilder.new(credentials).with_max_timeout(1)\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### soda-ruby\n\n```ruby\nSODA::Client.new(timeout: 1)\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### soundcloud\n\nNot configurable at the moment, and no timeout by default\n\n### stripe\n\n```ruby\nStripe.open_timeout = 1\nStripe.read_timeout = 1\n```\n\nDefault: 30s connect timeout, 80s read timeout\n\nRaises `Stripe::APIConnectionError`\n\n### tamber\n\n```ruby\nTamber.open_timeout = 1\nTamber.read_timeout = 1\n```\n\nRaises `Tamber::NetworkError`\n\n### twilio-ruby\n\n```ruby\nhttp_client = Twilio::HTTP::Client.new(timeout: 1)\nTwilio::REST::Client.new(account_sid, auth_token, nil, nil, http_client)\n```\n\nDefault: 30s\n\nRaises `Twilio::REST::TwilioError`\n\n### twitter\n\n```ruby\nTwitter::REST::Client.new do |config|\n  config.timeouts = {connect: 1, read: 1, write: 1}\nend\n```\n\nRaises `HTTP::TimeoutError`\n\n**Note:** All three timeouts must be set for any to take effect.\n\n### yt\n\nNot configurable at the moment, and no timeout by default\n\n### zendesk_api\n\n```ruby\nZendeskAPI::Client.new do |config|\n  config.client_options = {request: {open_timeout: 1, timeout: 1}}\nend\n```\n\nDefault: 10s connect timeout, no read timeout\n\nRaises `ZendeskAPI::Error::NetworkError`\n\n## Other\n\n### acme-client\n\n```ruby\nAcme::Client.new(connection_options: {request: {open_timeout: 1, timeout: 1}})\n```\n\nRaises `Acme::Client::Error::Timeout`\n\n### actionmailer\n\n```ruby\nActionMailer::Base.smtp_settings = {\n  open_timeout: 1,\n  read_timeout: 1\n}\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### activemerchant\n\n```ruby\nActiveMerchant::Billing::Gateway.open_timeout = 1\nActiveMerchant::Billing::Gateway.read_timeout = 1\n```\n\nDefault: 60s\n\nRaises `ActiveMerchant::ConnectionError`\n\n### activeresource\n\n```ruby\nclass Person \u003C ActiveResource::Base\n  self.open_timeout = 1\n  self.read_timeout = 1\nend\n```\n\nRaises `ActiveResource::TimeoutError`\n\n### carrot2\n\n```ruby\nCarrot2.new(open_timeout: 1, read_timeout: 1)\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### docker-api\n\n```ruby\nDocker.options = {\n  connect_timeout: 1,\n  read_timeout: 1\n}\n```\n\nRaises `Docker::Error::TimeoutError`\n\n### etcd\n\n```ruby\nclient = Etcd.client(read_timeout: 1)\n```\n\nConnect timeout not configurable\n\nDefault: 60s read timeout\n\nRaises\n\n- `Net::ReadTimeout` on read timeout\n\n### etcdv3\n\n```ruby\nEtcdv3.new(command_timeout: 1)\n```\n\nor\n\n```ruby\nconn.get(key, timeout: 1)\n```\n\nRaises `GRPC::DeadlineExceeded`\n\n### fastimage\n\n```ruby\nFastImage.size(url, timeout: 1)\n```\n\nReturns `nil` on timeouts\n\nIf you pass `raise_on_failure: true`, raises `FastImage::ImageFetchFailure`\n\n### geocoder\n\n```ruby\nGeocoder.configure(timeout: 1, ...)\n```\n\nNo exception is raised by default. To raise exceptions, use\n\n```ruby\nGeocoder.configure(timeout: 1, always_raise: :all, ...)\n```\n\nRaises `Geocoder::LookupTimeout`\n\n### graphql-client\n\n```ruby\nGraphQL::Client::HTTP.new(url) do\n  def connection\n    conn = super\n    conn.open_timeout = 1\n    conn.read_timeout = 1\n    conn\n  end\nend\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### grpc\n\n```ruby\nRouteGuide::Stub.new(addr, :this_channel_is_insecure, timeout: 1)\n```\n\nRaises `GRPC::DeadlineExceeded`\n\n### hexspace\n\n```ruby\nHexspace::Client.new(timeout: 1)\n```\n\nRaises `Thrift::TransportException`\n\n### ignite-client\n\n```ruby\nIgnite::Client.new(connect_timeout: 1)\n```\n\nRead timeout is not configurable at the moment\n\nRaises `Ignite::TimeoutError` on connect timeout\n\n### kubeclient\n\n```ruby\nKubeclient::Client.new(url, timeouts: {open: 1, read: 1})\n```\n\nRaises `KubeException`\n\nDefault: 60s connect timeout, 60s read timeout\n\n### mail\n\n```ruby\nMail.defaults do\n  delivery_method :smtp, open_timeout: 1, read_timeout: 1\nend\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### mechanize\n\n```ruby\nagent = Mechanize.new\nagent.open_timeout = 1\nagent.read_timeout = 1\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### nats-pure\n\n```ruby\nnats = NATS::IO::Client.new\nnats.connect(connect_timeout: 1)\n```\n\nRaises `NATS::IO::SocketTimeoutError`\n\n### nestful\n\n```ruby\nNestful::Request.new(url, timeout: 1)\n```\n\nor\n\n```ruby\nclass Resource \u003C Nestful::Resource\n  options timeout: 1\nend\n```\n\nRaises `Nestful::TimeoutError`\n\n### net-dns\n\n```ruby\nNet::DNS::Resolver.new(udp_timeout: 1)\n```\n\nDefault: 5s\n\nRaises `Net::DNS::Resolver::NoResponseError`\n\n### net-ldap\n\n```ruby\nNet::LDAP.new(host: host, connect_timeout: 1)\n```\n\nRead timeout [not configurable at the moment](https:\u002F\u002Fgithub.com\u002Fruby-ldap\u002Fruby-net-ldap\u002Fpull\u002F167)\n\nDefault: 5s connect timeout, no read timeout\n\nRaises `Net::LDAP::Error`\n\n### net-ntp\n\n```ruby\ntimeout = 1\nNet::NTP.get(host, port, timeout)\n```\n\nRaises `Timeout::Error`\n\n### net-scp\n\n```ruby\nNet::SCP.start(host, user, timeout: 1)\n```\n\nRaises `Net::SSH::ConnectionTimeout`\n\n### net-sftp\n\n```ruby\nNet::SFTP.start(host, user, timeout: 1)\n```\n\nRaises `Net::SSH::ConnectionTimeout`\n\n### net-ssh\n\n```ruby\nNet::SSH.start(host, user, timeout: 1)\n```\n\nRaises `Net::SSH::ConnectionTimeout`\n\n### net-telnet\n\n```ruby\nNet::Telnet::new(\"Host\" => host, \"Timeout\" => 1)\n```\n\nRaises\n\n- `Net::OpenTimeout` on connect timeout\n- `Net::ReadTimeout` on read timeout\n\n### omniauth-oauth2\n\n[Not configurable at the moment](https:\u002F\u002Fgithub.com\u002Fintridea\u002Fomniauth-oauth2\u002Fissues\u002F27), and no timeout by default\n\n### rbhive\n\n```ruby\nRBHive.tcli_connect(host, port, timeout: 1) do |connection|\n  # ...\nend\n```\n\nRaises `Thrift::TransportException`\n\n### reversed\n\n```ruby\nReversed.lookup(\"8.8.8.8\", timeout: 1)\n```\n\nReturns `nil` on timeouts\n\n### savon\n\n```ruby\nSavon.client(wsdl: url, open_timeout: 1, read_timeout: 1)\n```\n\nRaises\n\n- `HTTPClient::ConnectTimeoutError` on connect timeout\n- `HTTPClient::ReceiveTimeoutError` on read timeout\n\n### spydr\n\n```ruby\nSpidr.open_timeout = 1\nSpidr.read_timeout = 1\n```\n\nNo exception is raised. Check for failures with\n\n```ruby\nagent = Spidr.site(url)\nagent.failures\n```\n\n### spyke\n\n```ruby\nSpyke::Base.connection = Faraday.new(url: url) do |c|\n  c.adapter Faraday.default_adapter\n  c.options[:open_timeout] = 1\n  c.options[:timeout] = 1\nend\n```\n\nRaises `Spyke::ConnectionError`\n\n### stomp\n\n```ruby\nStomp::Client.new(start_timeout: 1, connect_timeout: 1, connread_timeout: 1, parse_timeout: 1)\n```\n\nRaises\n\n- `Stomp::Error::StartTimeoutException` on connect timeout\n- `Stomp::Error::ReceiveTimeout` on read timeout\n\n### thrift\n\n```ruby\nThrift::Socket.new(host, port, 1)\n```\n\nRaises `Thrift::TransportException`\n\n### thrift_client\n\n```ruby\nThriftClient.new(client_class, servers, connect_timeout: 1, timeout: 1)\n```\n\nRaises\n\n- `ThriftClient::NoServersAvailable` on connect timeout\n- TODO: read timeout\n\n### vault\n\n```ruby\nVault.configure do |config|\n  config.timeout = 1\n\n  # or more granular\n  config.ssl_timeout  = 1\n  config.open_timeout = 1\n  config.read_timeout = 1\nend\n```\n\nRaises `Vault::HTTPConnectionError`\n\n### whois\n\n```ruby\nWhois::Client.new(timeout: 1)\n```\n\nDefault: 10s\n\nRaises `Timeout::Error`\n\n### zk\n\n[Not configurable at the moment](https:\u002F\u002Fgithub.com\u002Fzk-ruby\u002Fzk\u002Fissues\u002F87)\n\nDefault: 30s\n\nRaises `Zookeeper::Exceptions::ContinuationTimeoutError`\n\n### zookeeper\n\n[Not configurable at the moment](https:\u002F\u002Fgithub.com\u002Fzk-ruby\u002Fzookeeper\u002Fissues\u002F38)\n\nDefault: 30s\n\nRaises `Zookeeper::Exceptions::ContinuationTimeoutError`\n\n## Don’t see a library you use?\n\n[Let us know](https:\u002F\u002Fgithub.com\u002Fankane\u002Fruby-timeouts\u002Fissues\u002Fnew). Even better, [create a pull request](https:\u002F\u002Fgithub.com\u002Fankane\u002Fruby-timeouts\u002Fpulls) for it.\n\n## Rescuing Exceptions\n\nTake advantage of inheritance. Instead of\n\n```ruby\nrescue Net::OpenTimeout, Net::ReadTimeout\n```\n\nyou can do\n\n```ruby\nrescue Timeout::Error\n```\n\nUse\n\n- `Timeout::Error` for both `Net::OpenTimeout` and `Net::ReadTimeout`\n- `Faraday::ClientError` for both `Faraday::ConnectionFailed` and `Faraday::TimeoutError`\n- `HTTPClient::TimeoutError` for both `HTTPClient::ConnectTimeoutError` and `HTTPClient::ReceiveTimeoutError`\n- `Redis::BaseConnectionError` for both `Redis::CannotConnectError` and `Redis::TimeoutError`\n- `Rack::Timeout::Error` for both `Rack::Timeout::RequestTimeoutError` and `Rack::Timeout::RequestExpiryError`\n- `RestClient::Exceptions::Timeout` for both `RestClient::Exceptions::OpenTimeout` and `RestClient::Exceptions::ReadTimeout`\n\n## Existing Services\n\nAdding timeouts to existing services can be a daunting task, but there’s a low risk way to do it.\n\n1. Select a timeout - say 5 seconds\n2. Log instances exceeding the proposed timeout\n3. Fix them\n4. Add the timeout\n5. Repeat this process with a lower timeout, until your target timeout is achieved\n\n## Running the Tests\n\n```sh\ngit clone https:\u002F\u002Fgithub.com\u002Fankane\u002Fthe-ultimate-guide-to-ruby-timeouts.git\ncd the-ultimate-guide-to-ruby-timeouts\nbundle install\n```\n\nTo run all tests, use:\n\n```sh\nbundle exec appraisal rake test\n```\n\nTo run individual tests, use:\n\n```sh\nbundle exec appraisal faraday rake test\n```\n\nTo add a new gem:\n\n1. Add it to `Appraisals` and run `bundle exec appraisal generate`\n2. Run `bundle exec appraisal new_gem bundle`\n3. Create `test\u002Fnew_gem_test.rb` and run `bundle exec appraisal new_gem rake test`\n4. Add it to the appropriate section of the readme\n\n## And lastly...\n\n> Because time is not going to go backwards, I think I better stop now. - Stephen Hawking\n\n:clock4:\n","该项目提供了为常用 Ruby 宝石添加超时设置的方法，旨在避免因服务无响应导致整个系统被占用。其核心功能包括为多种类型的网络请求（如连接、读取、写入等）配置超时，并且强调了避免使用 Ruby 自带的 `Timeout` 模块的重要性，因为该模块存在潜在风险。此外，项目还特别关注数据库语句执行超时的设置，这对依赖关系型数据库的应用尤为重要。此项目适用于任何需要提高 Ruby 应用稳定性和可靠性的场景，尤其是那些涉及大量外部服务调用或数据库操作的应用程序。",2,"2026-06-11 03:15:23","top_language"]