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 Go packages. All have been tested. The default is no timeout, unless otherwise specified. Enjoy!
Also available for Ruby, Python, Node, and Rust
Standard library
github.com
- aws/aws-sdk-go
- aws/aws-sdk-go-v2
- bradfitz/gomemcache
- couchbase/gocb
- elastic/go-elasticsearch
- emersion/go-smtp
- gocql/gocql
- go-pg/pg
- go-redis/redis
- go-sql-driver/mysql
- opensearch-project/opensearch-go
Other
conn, err := net.DialTimeout(network, address, time.Second)
if err != nil {
// handle error
}
err = conn.SetDeadline(time.Now().Add(time.Second))
client := http.Client{
Timeout: time.Second,
}
conn, err := net.DialTimeout("tcp", address, time.Second)
if err != nil {
// handle error
}
err = conn.SetDeadline(time.Now().Add(time.Second))
if err != nil {
// handle error
}
client, err = smtp.NewClient(conn, host)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
err := exec.CommandContext(ctx, cmd).Run()
sess := session.Must(session.NewSession(&aws.Config{
HTTPClient: &http.Client{Timeout: time.Second},
}))
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithHTTPClient(&http.Client{Timeout: time.Second}),
)
mc := memcache.New(host)
mc.Timeout = time.Second
cluster, err := gocb.Connect(connStr, gocb.ClusterOptions{
TimeoutsConfig: gocb.TimeoutsConfig{
ConnectTimeout: time.Second,
KVTimeout: time.Second,
ViewTimeout: time.Second,
QueryTimeout: time.Second,
AnalyticsTimeout: time.Second,
SearchTimeout: time.Second,
ManagementTimeout: time.Second,
},
})
See the docs for defaults
cfg := elasticsearch.Config{
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: time.Second,
}).DialContext,
ResponseHeaderTimeout: time.Second,
},
}
es, err := elasticsearch.NewClient(cfg)
conn, err := net.DialTimeout("tcp", address, time.Second)
if err != nil {
// handle error
}
err = conn.SetDeadline(time.Now().Add(time.Second))
if err != nil {
// handle error
}
client, err = smtp.NewClient(conn, host)
cluster := gocql.NewCluster(host)
cluster.ConnectTimeout = time.Second
cluster.Timeout = time.Second
Default: 600ms connect timeout, 600ms read timeout
db := pg.Connect(&pg.Options{
DialTimeout: time.Second,
ReadTimeout: time.Second,
WriteTimeout: time.Second,
})
rdb := redis.NewClient(&redis.Options{
DialTimeout: time.Second,
ReadTimeout: time.Second,
WriteTimeout: time.Second,
})
cfg := mysql.Config{
Timeout: time.Second,
ReadTimeout: time.Second,
WriteTimeout: time.Second,
}
db, err := sql.Open("mysql", cfg.FormatDSN())
cfg := opensearch.Config{
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: time.Second,
}).DialContext,
ResponseHeaderTimeout: time.Second,
},
}
client, err := opensearch.NewClient(cfg)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
Let us know. Even better, create a pull request for it.
git clone https://github.com/ankane/go-timeouts.git
cd go-timeouts
go mod tidy
To run all tests, use:
go test ./... -v
To run individual tests, use:
go test test/helper_test.go test/net_http_test.go -v