1

I`m trying to create a Golang net/http based web service, which takes a JSON input from user, and then it queries a third party web API itselves, to get data and then returns answer to client. I use http.Client{} client.Do() method to query the third party web API. When I perform a performance test (JMeter), very often I get the error: connectex: Only one usage of each socket address (protocol/network address/port) is normally permitted. I suspected the race state, but race detection shows no state of race. To my mind, posting HTTP requests too often, may cause port exhaustion over time. So, I tried to balance queries between two or three instances (hosts). However, I still get the error rather often. Is there a way to avoid this error? Is there any architecture trick, to make my service high-load ready? You can see the simplified code example below:

var upstream = []string{"1.1.1.1", "2.2.2.2", "3.3.3.3"}
var scheme = "http"
var timeout = 5

    func main() {
        fmt.Println("Listening on *: 8080")
        http.HandleFunc("/", handler)
        log.Fatal(http.ListenAndServe(":8080", nil))
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
    
        if r.Method != "POST" {
            http.Error(w, http.StatusText(405), 405)
            return
        }
    
        body, err := ioutil.ReadAll(r.Body)
        if err != nil {
            fmt.Println("Error:", err)
            http.Error(w, http.StatusText(400), 400)
            return
        }
    
        var jsonEntity = make(map[string]string)
    
        json.Unmarshal(body, &jsonEntity)
    
        payload := bytes.NewReader(body)
    
        url := r.URL
        url.Host = upstream[0]
        if len(upstream) > 1 {
            url.Host = upstream[random(0, len(upstream))]
        }
        url.Scheme = scheme
    
    
        proxyReq, err := http.NewRequest(http.MethodPost, url.String(), payload)
        if err != nil {
            fmt.Println("Error:", err)
            http.Error(w, http.StatusText(400), 400)
            return
        }
    
        client := http.Client{Timeout: time.Duration(timeout) * time.Second}
    
        response, err := client.Do(proxyReq) // <- IT FAILS HERE!!!
        if err != nil {                 
            fmt.Println("Error:", err)
            http.Error(w, http.StatusText(500), 500)
            sendWithCheck(w, "%s", []byte(`{"answerParam":"error"}`))
            return
        }
        defer func() {
            if err := response.Body.Close(); err != nil {
                log.Println("Error:", err)
            }
        }()
    
        res, err := ioutil.ReadAll(response.Body)
        if err != nil {
            fmt.Println("Error:", err)
            http.Error(w, http.StatusText(500), 500)
            sendWithCheck(w, "%s", []byte(`{"answerParam":"error"}`))
            return
        }
    
        if response.StatusCode == 200 {
            sendWithCheck(w, "%s", res)
            return
        }
    
        w.WriteHeader(response.StatusCode)
        return
    }
  • 2
    see here: https://help.socketlabs.com/docs/how-to-fix-error-only-one-usage-of-each-socket-address-protocolnetwork-addressport-is-normally-permitted – Sean F Jul 03 '22 at 16:09

0 Answers0