Go Timeouts
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!
Packages
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
Standard Library
net
conn, err := net.DialTimeout(network, address, time.Second)
if err != nil {
// handle error
}
err = conn.SetDeadline(time.Now().Add(time.Second))
net/http
client := http.Client{
Timeout: time.Second,
}
net/smtp
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)
os/exec
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
err := exec.CommandContext(ctx, cmd).Run()
github.com
aws/aws-sdk-go
sess := session.Must(session.NewSession(&aws.Config{
HTTPClient: &http.Client{Timeout: time.Second},
}))
aws/aws-sdk-go-v2
cfg, err := config.LoadDefaultConfig(context.TODO(),
config.WithHTTPClient(&http.Client{Timeout: time.Second}),
)
bradfitz/gomemcache
mc := memcache.New(host)
mc.Timeout = time.Second
couchbase/gocb
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
elastic/go-elasticsearch
cfg := elasticsearch.Config{
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: time.Second,
}).DialContext,
ResponseHeaderTimeout: time.Second,
},
}
es, err := elasticsearch.NewClient(cfg)
emersion/go-smtp
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)
gocql/gocql
cluster := gocql.NewCluster(host)
cluster.ConnectTimeout = time.Second
cluster.Timeout = time.Second
Default: 600ms connect timeout, 600ms read timeout
go-pg/pg
db := pg.Connect(&pg.Options{
DialTimeout: time.Second,
ReadTimeout: time.Second,
WriteTimeout: time.Second,
})
go-redis/redis
rdb := redis.NewClient(&redis.Options{
DialTimeout: time.Second,
ReadTimeout: time.Second,
WriteTimeout: time.Second,
})
go-sql-driver/mysql
cfg := mysql.Config{
Timeout: time.Second,
ReadTimeout: time.Second,
WriteTimeout: time.Second,
}
db, err := sql.Open("mysql", cfg.FormatDSN())
opensearch-project/opensearch-go
cfg := opensearch.Config{
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: time.Second,
}).DialContext,
ResponseHeaderTimeout: time.Second,
},
}
client, err := opensearch.NewClient(cfg)
Other
go.mongodb.org/mongo-driver/mongo
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
client, err := mongo.Connect(ctx, options.Client().ApplyURI(uri))
Don’t see a library you use?
Let us know. Even better, create a pull request for it.
Running the Tests
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