Reputation: 66
Implemented a context timeout in Go APIs using
context.WithTimeout(context,time)
Expectation is that if I set it to 10 seconds and if the API happens to run longer, it should stop and return Timeout error. However, if I add a sleep in between , the API still runs and gives 200 output. Is there any solution to this other than manually checking at random points for the time elapsed ? Looks like context.WithTimeout() doesnt solve its purpose.
Upvotes: 0
Views: 1124
Reputation: 1861
So, this is a minimum code to exemplify how the context.WithTimeout can work:
server.go
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
http.HandleFunc("/bad", badResponse)
http.HandleFunc("/nice", niceResponse)
http.ListenAndServe(":8099", nil)
}
// badResponse is a procedure that takes too much time
func badResponse(w http.ResponseWriter, r *http.Request) {
fmt.Println("got request, it may take too long to answer")
time.Sleep(3 * time.Second)
fmt.Fprintf(w, "bad response!")
}
// niceResponse is a procedure that respond in time
func niceResponse(w http.ResponseWriter, r *http.Request) {
fmt.Println("got request, will return fast")
fmt.Fprintf(w, "nice response!")
}
client.go
package main
import (
"context"
"io/ioutil"
"log"
"net/http"
"time"
)
func main () {
req, err := http.NewRequest(http.MethodGet, "http://localhost:8099/bad", nil)
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
req = req.WithContext(ctx)
c := &http.Client{}
res, err := c.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
out, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatal(err)
}
log.Println(string(out))
}
In the example above the client must fail because the timeout is lower than the client server delay.
Upvotes: 1