I am a golang novice... I am trying to write an application that takes in many requests - up to a sustained 10000 HTTP posts/sec and post the payload to two back-ends in parallel (5 second timeout). A canned message is returned to the client, it doesn't matter whether the backed end returns a response or errors out, the same response text is sent to the client.
I have a first crack at it below. I'm not worried about error handling yet. My thinking is that I can make each back-end call asynchronous using goroutines and let the go runtime deal with queuing/threads for the go routines. I simply need to perform the post and log the result, there is no communication between goroutines. I have had others guide me to using channels, but given that I don't need to return any data back from the post I'm not sure I need them.
Here is my first very simple crack at it. Please make any suggestions on the code and approach!
package main
import (
"fmt"
"github.com/go-chi/chi"
"net/http"
"io/ioutil"
"bytes"
"time"
)
func main() {
r := chi.NewRouter()
r.Post("/", func(w http.ResponseWriter, r *http.Request) {
handlePost(w, r);
})
http.ListenAndServe(":3000", r)
}
func handlePost(w http.ResponseWriter, r *http.Request) {
body, _ := ioutil.ReadAll(r.Body)
fmt.Fprintf(w, "dummy response will go here");
go callBackend("http://backend1", body)
go callBackend("http://backend2", body)
}
func callBackend(url string, body []byte) {
req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
req.Header.Set("Content-Type", "application/xml")
client := &http.Client{
Timeout: time.Second * 5,
}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Sprintf("backend [%s] response status: %s", url, resp.Status)
fmt.Println("backend response Headers:", resp.Header)
responsebody, _ := ioutil.ReadAll(resp.Body)
fmt.Println("backend response Body:", string(responsebody))
}
1 Answer 1
r.Post("/", func(w http.ResponseWriter, r *http.Request) {
handlePost(w, r)
})
can be simplified to
r.Post("/", handlePost)
since both functions have same signature.
fmt.Fprintf(w, "dummy response will go here")
No need to use printf
family functions where you don't need formatting. You can write directly with
w.Write([]byte("dummy response will go here"))
or with
io.WriteString(w, "dummy response will go here")
responsebody, _ := ioutil.ReadAll(resp.Body)
fmt.Println("backend response Body:", string(responsebody))
This one reads the whole response into memory for no reason. Use io.Copy
to write it more efficiently:
fmt.Print("backend response Body: ")
_, err := io.Copy(os.Stdout, resp.Body)
I'm not worried about error handling yet.
Then everything else is totally fine.