9
9
10
10
"github.com/graphql-go/graphql/gqlerrors"
11
11
"github.com/graphql-go/graphql/language/ast"
12
+ "sync"
12
13
)
13
14
14
15
type ExecuteParams struct {
@@ -110,6 +111,15 @@ type ExecutionContext struct {
110
111
VariableValues map [string ]interface {}
111
112
Errors []gqlerrors.FormattedError
112
113
Context context.Context
114
+
115
+ errorsMutex sync.Mutex
116
+ resolveWaitGroup sync.WaitGroup
117
+ }
118
+
119
+ func (eCtx * ExecutionContext ) addError (err gqlerrors.FormattedError ) {
120
+ eCtx .errorsMutex .Lock ()
121
+ defer eCtx .errorsMutex .Unlock ()
122
+ eCtx .Errors = append (eCtx .Errors , err )
113
123
}
114
124
115
125
func buildExecutionContext (p BuildExecutionCtxParams ) (* ExecutionContext , error ) {
@@ -278,13 +288,38 @@ func executeFields(p ExecuteFieldsParams) *Result {
278
288
p .Fields = map [string ][]* ast.Field {}
279
289
}
280
290
291
+ var numberOfDeferredFunctions int
292
+ recoverChan := make (chan interface {}, len (p .Fields ))
293
+
294
+ var resultsMutex sync.Mutex
281
295
finalResults := map [string ]interface {}{}
282
296
for responseName , fieldASTs := range p .Fields {
283
297
resolved , state := resolveField (p .ExecutionContext , p .ParentType , p .Source , fieldASTs )
284
298
if state .hasNoFieldDefs {
285
299
continue
286
300
}
287
- finalResults [responseName ] = resolved
301
+ if resolve , ok := resolved .(deferredResolveFunction ); ok {
302
+ numberOfDeferredFunctions += 1
303
+ go func () {
304
+ defer func () {
305
+ recoverChan <- recover ()
306
+ }()
307
+
308
+ resultsMutex .Lock ()
309
+ defer resultsMutex .Unlock ()
310
+ finalResults [responseName ] = resolve ()
311
+ }()
312
+ } else {
313
+ resultsMutex .Lock ()
314
+ finalResults [responseName ] = resolved
315
+ resultsMutex .Unlock ()
316
+ }
317
+ }
318
+
319
+ for i := 0 ; i < numberOfDeferredFunctions ; i ++ {
320
+ if r := <- recoverChan ; r != nil {
321
+ panic (r )
322
+ }
288
323
}
289
324
290
325
return & Result {
@@ -503,32 +538,36 @@ type resolveFieldResultState struct {
503
538
hasNoFieldDefs bool
504
539
}
505
540
541
+ type deferredResolveFunction func () interface {}
542
+
506
543
// Resolves the field on the given source object. In particular, this
507
544
// figures out the value that the field returns by calling its resolve function,
508
545
// then calls completeValue to complete promises, serialize scalars, or execute
509
546
// the sub-selection-set for objects.
510
547
func resolveField (eCtx * ExecutionContext , parentType * Object , source interface {}, fieldASTs []* ast.Field ) (result interface {}, resultState resolveFieldResultState ) {
511
548
// catch panic from resolveFn
512
549
var returnType Output
550
+ handleRecover := func (r interface {}) {
551
+ var err error
552
+ if r , ok := r .(string ); ok {
553
+ err = NewLocatedError (
554
+ fmt .Sprintf ("%v" , r ),
555
+ FieldASTsToNodeASTs (fieldASTs ),
556
+ )
557
+ }
558
+ if r , ok := r .(error ); ok {
559
+ err = gqlerrors .FormatError (r )
560
+ }
561
+ // send panic upstream
562
+ if _ , ok := returnType .(* NonNull ); ok {
563
+ panic (gqlerrors .FormatError (err ))
564
+ }
565
+ eCtx .addError (gqlerrors .FormatError (err ))
566
+ }
567
+
513
568
defer func () (interface {}, resolveFieldResultState ) {
514
569
if r := recover (); r != nil {
515
-
516
- var err error
517
- if r , ok := r .(string ); ok {
518
- err = NewLocatedError (
519
- fmt .Sprintf ("%v" , r ),
520
- FieldASTsToNodeASTs (fieldASTs ),
521
- )
522
- }
523
- if r , ok := r .(error ); ok {
524
- err = gqlerrors .FormatError (r )
525
- }
526
- // send panic upstream
527
- if _ , ok := returnType .(* NonNull ); ok {
528
- panic (gqlerrors .FormatError (err ))
529
- }
530
- eCtx .Errors = append (eCtx .Errors , gqlerrors .FormatError (err ))
531
- return result , resultState
570
+ handleRecover (r )
532
571
}
533
572
return result , resultState
534
573
}()
@@ -580,6 +619,25 @@ func resolveField(eCtx *ExecutionContext, parentType *Object, source interface{}
580
619
panic (gqlerrors .FormatError (resolveFnError ))
581
620
}
582
621
622
+ if deferredResolveFn , ok := result .(func () (interface {}, error )); ok {
623
+ return deferredResolveFunction (func () (result interface {}) {
624
+ defer func () interface {} {
625
+ if r := recover (); r != nil {
626
+ handleRecover (r )
627
+ }
628
+
629
+ return result
630
+ }()
631
+
632
+ result , resolveFnError = deferredResolveFn ()
633
+ if resolveFnError != nil {
634
+ panic (gqlerrors .FormatError (resolveFnError ))
635
+ }
636
+
637
+ return completeValueCatchingError (eCtx , returnType , fieldASTs , info , result )
638
+ }), resultState
639
+ }
640
+
583
641
completed := completeValueCatchingError (eCtx , returnType , fieldASTs , info , result )
584
642
return completed , resultState
585
643
}
@@ -593,7 +651,7 @@ func completeValueCatchingError(eCtx *ExecutionContext, returnType Type, fieldAS
593
651
panic (r )
594
652
}
595
653
if err , ok := r .(gqlerrors.FormattedError ); ok {
596
- eCtx .Errors = append ( eCtx . Errors , err )
654
+ eCtx .addError ( err )
597
655
}
598
656
return completed
599
657
}
0 commit comments