5
\$\begingroup\$

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))
}
asked Jul 20, 2018 at 21:18
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$
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.

answered Aug 13, 2018 at 18:41
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.