Appreciate a response from a senior level architect who has a deep understanding of concurrency and experience in go language
I've a custom apparatus to handle, process and respond to incoming client requests and server is simply wrapping all the incoming requests, the request
and responseWriter
in an object and delegating to the apparatus.
The problem I'm observing based on my unit tests (spawning 1000 http request to localhost) is that all the requests are processed in sequence instead concurrently, it's like they are in
Each request is taking more time than the previous one simply telling me it's a queue. If for example a database based request takes 200 ms
.
Request 1 -> taking 200 ms
Request 2 -> taking 400 ms
Request 3 -> taking 600 ms
Each request is waiting for the previous request to finish, I'm not doing something right when it comes to delegating incoming requests to the apparatus so I've prepared a trimmed down version that simply decodes the JWT token and responds to the client, please run test/token_test.go. Download Project
application.go
func main() {
a := delegate.Apparatus{}
a.Run()
}
apparatus.go
type Apparatus struct {}
func (a *Apparatus) Run() { // initialize the server
server := Server{}
server.SetDelegate(a) // tell server to forward requests to itself
server.StartServer() // start the server
}
func (a *Apparatus) Handle(request *Request) { // interface impl
a.RenewToken(request) // delegate request to a time consuming func
}
server.go
type Server struct {}
func (s *Server) StartServer() {
http.HandleFunc("/", handler)
fmt.Println("Server Listening at 8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal(err)
}
}
func handler(w http.ResponseWriter, r *http.Request) { // delegate to apparatus
delegate.Handle(&Request{ResponseWriter: w, Request: r})
}
func (s *Server) SetDelegate(d IHandler) {
delegate = d
}
request.go wrapper for the request
and responseWriter
type Request struct {
ResponseWriter http.ResponseWriter
Request *http.Request
}
ihandler.go interface for the apparatus
type IHandler interface {
Handle(request *Request)
}
test/token_test.go this will show each successive request is taking more and more time than the previous one
func MakeRequest(ch chan<-int, index int) {
t0 := time.Now()
response, _ := http.Get("http://localhost:8080?authToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Mjg4LCJuYmYiOjE0NDQ0Nzg0MDAsInJhbmQiOjAuOTI2OTg2ODAzNTc0NDE0Mn0.3HC8lEDGlui_sOtkeMn52Wnt9HUuH4lFbk7ubdUK_Z4&index=" + strconv.Itoa(index))
t1 := time.Now()
ch <- response.StatusCode
fmt.Printf("The call took %v to run.
", t1.Sub(t0))
}
func TestConcurrent(t *testing.T) {
start := time.Now()
ch := make(chan int)
max := 1000
for i:=0; i<max; i++ {
go MakeRequest(ch, i)
}
for i:=0; i<max; i++ {
if <-ch != 200 {t.Error("Expecting status code 200")}
}
fmt.Printf("%.2fs elapsed", time.Since(start).Seconds())
}
It's best to download the project and test. I suspect the problem is in the server.go (line 24). I'm not delegating the request in a right way and they are simply queuing up.
Solution I'm looking for is how can I delegate/forward the incoming requests concurrently.