Skip to content

Commit

Permalink
fix: race and limit per-request concurrency
Browse files Browse the repository at this point in the history
  • Loading branch information
danielgtaylor committed Mar 4, 2022
1 parent 75cb6c5 commit 33ddff3
Showing 1 changed file with 13 additions and 3 deletions.
16 changes: 13 additions & 3 deletions graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
type graphContextKey string

var graphKeyHeaders graphContextKey = "headers"
var graphKeySem graphContextKey = "sem"

type GraphQLConfig struct {
// Path where the GraphQL endpoint is available. Defaults to `/graphql`.
Expand Down Expand Up @@ -252,19 +253,26 @@ func (r *Router) handleOperation(config *GraphQLConfig, parentName string, field
}
}

// Use a per-request semaphore to limit the number of concurrent
// goroutines used to fetch data to satisfy that request.
sem := p.Context.Value(graphKeySem).(chan int)
sem <- 1

// Fire off the request but don't wait for the response. Instead, we
// return a "thunk" which is a function to be resolved later (like a js
// Promise) which GraphQL resolves *after* visiting all fields in
// breadth-first order. This ensures we kick off all the requests in
// parallel but then wait for all the results until processing deeper
// into the query.
// See also https://github.com/graphql-go/graphql/pull/388.
done := make(chan bool)
done := make(chan bool, 1)
var result interface{}
var respHeader http.Header
var err error
go func() {
result, respHeader, err = r.fetch(headers, path, queryParams)
result, respHeader, err = r.fetch(headers.Clone(), path, queryParams)
done <- true
<-sem
}()

return func() (interface{}, error) {
Expand Down Expand Up @@ -392,7 +400,9 @@ func (r *Router) EnableGraphQL(config *GraphQLConfig) {
r.mux.HandleFunc(config.Path, func(w http.ResponseWriter, r *http.Request) {
// Save the headers for future requests as they can contain important
// information.
r = r.WithContext(context.WithValue(r.Context(), graphKeyHeaders, r.Header))
c := context.WithValue(r.Context(), graphKeyHeaders, r.Header)
c = context.WithValue(c, graphKeySem, make(chan int, 10))
r = r.WithContext(c)
h.ServeHTTP(w, r)
})
}

0 comments on commit 33ddff3

Please sign in to comment.