GraphQL: Unlock goroutine throttle to match batch capacity (#20146)

We were throttling the amount of concurrent resolvers
at a given time. The idea behind this was to avoid overloading
the database with too many requests.

However, with the introduction of dataloaders, this limitation
actually becomes a bottleneck because all DB calls are actually
batched, so we are unnecessarily throttling the amount of
items that can be processed in a single batch.

The only caveat with this is that now all resolvers
need to backed by dataloaders, or otherwise not be queried
as part of a loop.

In a subsequent PR, we will be removing channel stats
from under channel to be a top-level object to be returned
for a given channel.

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2022-05-06 21:53:29 +05:30
коммит произвёл GitHub
родитель a3af488492
Коммит fed5404166
13 изменённых файлов: 148 добавлений и 38 удалений

Просмотреть файл

@@ -14,6 +14,7 @@ import (
gqlerrors "github.com/graph-gophers/graphql-go/errors"
"github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/mattermost/mattermost-server/v6/web"
)
type graphQLInput struct {
@@ -22,6 +23,19 @@ type graphQLInput struct {
Variables map[string]interface{} `json:"variables"`
}
// Unique type to hold our context.
type ctxKey int
const (
webCtx ctxKey = 0
rolesLoaderCtx ctxKey = 1
channelsLoaderCtx ctxKey = 2
teamsLoaderCtx ctxKey = 3
usersLoaderCtx ctxKey = 4
)
const loaderBatchCapacity = web.PerPageMaximum + 100
//go:embed schema.graphqls
var schemaRaw string
@@ -35,7 +49,8 @@ func (api *API) InitGraphQL() error {
opts := []graphql.SchemaOpt{
graphql.UseFieldResolvers(),
graphql.Logger(mlog.NewGraphQLLogger(api.srv.Log)),
graphql.MaxParallelism(5),
graphql.MaxParallelism(loaderBatchCapacity), // This is dangerous if the query
// uses any non-dataloader backed object. So we need to be a bit careful here.
}
if isProd() {
@@ -58,18 +73,6 @@ func (api *API) InitGraphQL() error {
return nil
}
// Unique type to hold our context.
type ctxKey int
const (
webCtx ctxKey = 0
rolesLoaderCtx ctxKey = 1
channelsLoaderCtx ctxKey = 2
teamsLoaderCtx ctxKey = 3
)
const loaderBatchCapacity = 200
func (api *API) graphQL(c *Context, w http.ResponseWriter, r *http.Request) {
var response *graphql.Response
defer func() {
@@ -111,6 +114,9 @@ func (api *API) graphQL(c *Context, w http.ResponseWriter, r *http.Request) {
teamsLoader := dataloader.NewBatchedLoader(graphQLTeamsLoader, dataloader.WithBatchCapacity(loaderBatchCapacity))
reqCtx = context.WithValue(reqCtx, teamsLoaderCtx, teamsLoader)
usersLoader := dataloader.NewBatchedLoader(graphQLUsersLoader, dataloader.WithBatchCapacity(loaderBatchCapacity))
reqCtx = context.WithValue(reqCtx, usersLoaderCtx, usersLoader)
response = api.schema.Exec(reqCtx,
params.Query,
params.OperationName,