Skip to content

Commit

Permalink
Experimental implementation of concurrently resolving fields
Browse files Browse the repository at this point in the history
  • Loading branch information
sogko committed May 10, 2016
1 parent 09574d6 commit ab3b083
Showing 1 changed file with 41 additions and 5 deletions.
46 changes: 41 additions & 5 deletions executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,15 +274,51 @@ func executeFields(p ExecuteFieldsParams) *Result {
p.Fields = map[string][]*ast.Field{}
}

finalResults := map[string]interface{}{}
type resolvedChanResult struct {
responseName string
resolved interface{}
state resolveFieldResultState
panicErr error
}

// concurrently resolve fields
var wg sync.WaitGroup
resolvedChan := make(chan resolvedChanResult, len(p.Fields))
for responseName, fieldASTs := range p.Fields {
resolved, state := resolveField(p.ExecutionContext, p.ParentType, p.Source, fieldASTs)
if state.hasNoFieldDefs {
wg.Add(1)
go func(responseName string, fieldASTs []*ast.Field) (resolved interface{}, state resolveFieldResultState, panicErr error) {

This comment has been minimized.

Copy link
@andreas

andreas Jun 9, 2016

Could you omit the return values of the function, i.e. func(responseName, string, fieldASTs []*ast.Field) { ... }? As far as I can tell they are not used as the result is communicated via resolvedChan.

defer func() {
if r := recover(); r != nil {
if r, ok := r.(error); ok {

This comment has been minimized.

Copy link
@andreas

andreas Jun 9, 2016

What if a non-error is used as the panicked value? I would propose casting without the check which will re-panic if invalid (err = r.(error)), or let panicErr be of type interface{} instead.

// recover panic that was thrown by resolveFields(),
// indicating that we should short-circuit traversal chain later
panicErr = r
}
}
resolvedChan <- resolvedChanResult{responseName, resolved, state, panicErr}
wg.Done()
}()
resolved, state = resolveField(p.ExecutionContext, p.ParentType, p.Source, fieldASTs)
return resolved, state, panicErr
}(responseName, fieldASTs)
}

// wait for all routines to complete and then perform clean up
wg.Wait()
close(resolvedChan)

// iterate through resolved results
finalResults := map[string]interface{}{}
for result := range resolvedChan {
if result.panicErr != nil {
// short-circuit field resolution traversal chain
panic(result.panicErr)
}
if result.state.hasNoFieldDefs {
continue
}
finalResults[responseName] = resolved
finalResults[result.responseName] = result.resolved
}

return &Result{
Data: finalResults,
Errors: p.ExecutionContext.Errors(),
Expand Down

0 comments on commit ab3b083

Please sign in to comment.