Tuesday, September 27, 2022
HomeGolangSet HTTP consumer timeout in Go (Golang)

Set HTTP consumer timeout in Go (Golang)



An HTTP consumer timeout is a time restrict during which the server should course of the request and return the response. If the set timeout is exceeded, the HTTP consumer ought to cancel the request and report an error. This mechanism is essential in functions that run in a manufacturing atmosphere. It helps stop the applying from getting caught ready for a server response, which can take a very long time or not occur in any respect.

In Go, the usual HTTP consumer doesn’t set timeouts by default. It signifies that an app can watch for the server’s response ceaselessly. To forestall this, you need to all the time keep in mind to set a timeout in your HTTP consumer. And that is what we wish to do right here 🙂.

There are three eventualities of setting a timeout for HTTP requests that we’re going to cowl on this article:

  • Setting the identical timeout for all requests of a brand new http.Consumer.
  • Setting a separate time restrict for every new request.
  • Modifying timeout for default HTTP consumer utilized by many exterior API consumer packages.

Set timeout per HTTP consumer

If you wish to set the identical timeout for all requests of a brand new http.Consumer, initialize the consumer with the Timeout subject set, the place you specify the time restrict during which the request have to be processed.

Have a look at the instance:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
bundle most important

import (
    "log"
    "web/http"
    "time"
)

func timeout(w http.ResponseWriter, req *http.Request) {
    time.Sleep(5 * time.Second)
}

func server() {
    go func() {
        http.HandleFunc("/timeout", timeout)
        log.Deadly(http.ListenAndServe(":8090", nil))
    }()
}

func most important() {
    server()

    httpClient := http.Consumer{Timeout: 2 * time.Second}
    if _, err := httpClient.Get("http://localhost:8090/timeout"); err != nil {
        log.Deadly(err)
    }
}

In strains 9-18, we declare a brand new easy server whose solely process is to pause work for five seconds by calling the time.Sleep operate. Within the first line of the most important() operate, we begin this server. Within the remaining strains, we create a brand new http.Consumer with the Timeout subject set to 2 seconds and ship a brand new request to the created server.

So by sending a request with a 2-second timeout to a server that pauses for five seconds, we’ll get a timeout error:

Output:

2022/08/08 12:31:43 Get "http://localhost:8090/timeout": context deadline exceeded (Consumer.Timeout exceeded whereas awaiting headers)
exit standing 1

When you run the app with out the Timeout set, you’ll not get any error.

Set timeout per request

If you wish to set a timeout for a person request, create a brand new request Context utilizing the context.WithTimeout() operate. Then, create a brand new request with this context as an argument utilizing the http.NewRequestWithContext() constructor.

bundle most important

import (
    "context"
    "log"
    "web/http"
    "time"
)

// func server() {...} the identical as within the first instance...

func most important() {
    server()

    httpClient := http.Consumer{}

    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
    req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost:8090/timeout", nil)
    if err != nil {
        log.Deadly(err)
    }

    if _, err := httpClient.Do(req); err != nil {
        log.Deadly(err)
    }
}

The context.Context is an object that may be a widespread Go idea utilized by HTTP purchasers and servers to ship/obtain request-scoped values, cancellation, and deadline indicators to deeper layers of providers. In our case, the context is used to set the deadline for getting a response for a given new request.

Observe that along with the timeout worth, the context.WithTimeout() operate additionally takes a dad or mum context as an argument, which in our instance is a brand new empty context created with the context.Background() operate. Because of this, we obtain the context and the cancellation operate to launch assets related to it, which we name as a deferred operate cancel().

Since as within the earlier instance, we ship a request with a 2-second timeout to the server that pauses for five seconds, we get an identical error message:

Output:

2022/08/08 15:06:18 Get "http://localhost:8090/timeout": context deadline exceeded
exit standing 1

Set timeout for default HTTP consumer

Typically you need to use code that makes use of the default HTTP consumer: http.DefaultClient. Usually there is no such thing as a solution to change this code in order that it makes use of the custom-defined HTTP consumer, e.g. in exterior packages or in code the place backward compatibility have to be maintained. Happily, this doesn’t imply that we can’t outline a timeout for such a consumer. The instance beneath exhibits easy methods to do it.

bundle most important

import (
    "log"
    "web/http"
    "time"
)

// func server() {...} the identical as within the first instance...

func most important() {
    server()

    http.DefaultClient.Timeout = 2 * time.Second

    if _, err := http.Get("http://localhost:8090/timeout"); err != nil {
        log.Deadly(err)
    }
}

All you need to do is about the Timeout subject within the default HTTP consumer, after which all capabilities of the http bundle utilizing the default consumer will respect this timeout.

On this instance, you get the identical error message as when you set the timeout per HTTP consumer:

Output:

2022/08/09 09:48:58 Get "http://localhost:8090/timeout": context deadline exceeded (Consumer.Timeout exceeded whereas awaiting headers)
exit standing 1
RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments