Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set timeout for http.Get() requests in Golang?

Tags:

http

go

timeout

get

People also ask

How do you add timeout in Golang?

Syntax. The After function waits for d duration to finish and then it will return the current time on a channel. Consider the code shown below where we make use of the After function to register a timeout. package main import ( "fmt" "time" ) func timeConsuming() string { time.

How do I set HTTP request timeout?

on('timeout', function() { req. abort(); }); req. write('something'); req. end();

How do you handle timeout in Golang?

With Golang, the approach to handling this has become as simple as it gets. Without using any complicated code, we can handle timeouts by using channels for communication and the select statement for timeout decisions. For more details on the above features, you read the Golang documentation here.


Apparently in Go 1.3 http.Client has Timeout field

client := http.Client{
    Timeout: 5 * time.Second,
}
client.Get(url)

That's done the trick for me.


You need to set up your own Client with your own Transport which uses a custom Dial function which wraps around DialTimeout.

Something like (completely untested) this:

var timeout = time.Duration(2 * time.Second)

func dialTimeout(network, addr string) (net.Conn, error) {
    return net.DialTimeout(network, addr, timeout)
}

func main() {
    transport := http.Transport{
        Dial: dialTimeout,
    }

    client := http.Client{
        Transport: &transport,
    }

    resp, err := client.Get("http://some.url")
}

To add to Volker's answer, if you would also like to set the read/write timeout in addition to the connect timeout you can do something like the following

package httpclient

import (
    "net"
    "net/http"
    "time"
)

func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) {
    return func(netw, addr string) (net.Conn, error) {
        conn, err := net.DialTimeout(netw, addr, cTimeout)
        if err != nil {
            return nil, err
        }
        conn.SetDeadline(time.Now().Add(rwTimeout))
        return conn, nil
    }
}

func NewTimeoutClient(connectTimeout time.Duration, readWriteTimeout time.Duration) *http.Client {

    return &http.Client{
        Transport: &http.Transport{
            Dial: TimeoutDialer(connectTimeout, readWriteTimeout),
        },
    }
}

This code is tested and is working in production. The full gist with tests is available here https://gist.github.com/dmichael/5710968

Be aware that you will need to create a new client for each request because of the conn.SetDeadline which references a point in the future from time.Now()


If you want to do it per request, err handling ignored for brevity:

ctx, cncl := context.WithTimeout(context.Background(), time.Second*3)
defer cncl()

req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://google.com", nil)

resp, _ := http.DefaultClient.Do(req)

A quick and dirty way:

http.DefaultTransport.(*http.Transport).ResponseHeaderTimeout = time.Second * 45

This is mutating global state w/o any coordination. Yet it might be possibly okay for your url fetcher. Otherwise create a private instance of http.RoundTripper:

var myTransport http.RoundTripper = &http.Transport{
        Proxy:                 http.ProxyFromEnvironment,
        ResponseHeaderTimeout: time.Second * 45,
}

var myClient = &http.Client{Transport: myTransport}

resp, err := myClient.Get(url)
...

Nothing above was tested.


You may use https://github.com/franela/goreq which handles timeouts in a fashion and simple way.