Java made a huge mistake of having no network timeouts. A network request can block a thread forever. Even Python did the same. The language designers should have chosen some conservative appropriate numbers instead.
What’s surprising is that the Go language repeated it! Here’s a simple demo
Let’s first create a server that would block forever
// Usage: go run server.go package main import ( "fmt" "log" "net/http" "time" ) func main() { startWebServer(8080) } func startWebServer(port int) { http.HandleFunc("/block-forever", blockForeverHandler) log.Printf("Serving on port %d", port) log.Fatal("%s", http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) } func blockForeverHandler(w http.ResponseWriter, req *http.Request) { // Do nothing and block forever count := 0 for true { time.Sleep(1 * time.Second) count++ log.Printf("Blocked since %d seconds ago...", count) } }
Start the server in one shell with `go run server.go`, you can test it out by visiting http://localhost:8080/block-forever or by doing `curl http://localhost:8080/block-forever` in the shell.
Now, connect to that server in another shell with the following code.
// Usage: go run client.go package main import ( "log" "net/http" ) func main() { fetchData("http://localhost:8080/block-forever") } func fetchData(urlStr string) { log.Printf("Fetching data from %s", urlStr) _, err := http.Get(urlStr) if err != nil { log.Fatalln(err) } log.Printf("Received data from %s", urlStr) }
And wait for it complete, it won’t.
So what’s the fix? Add a timeout before making the request
// Usage: go run client.go package main import ( "log" "net/http" "time" ) func main() { fetchDataWithTimeout("http://localhost:8080/block-forever") } func fetchDataWithTimeout(urlStr string) { log.Printf("Fetching data from %s", urlStr) client := &http.Client{ Timeout: 15 * time.Second, } _, err := client.Get(urlStr) if err != nil { log.Fatalln(err) } log.Printf("Received data from %s", urlStr) }
This will demonstrate the correct behavior by failing with
Fetching data from http://localhost:8080/block-forever Get "http://localhost:8080/block-forever": context deadline exceeded (Client.Timeout exceeded while awaiting headers) exit status 1