Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deferred values inside Action.sequence are not resolved. #465

Open
danestig opened this issue Nov 6, 2019 · 1 comment
Open

Deferred values inside Action.sequence are not resolved. #465

danestig opened this issue Nov 6, 2019 · 1 comment

Comments

@danestig
Copy link

danestig commented Nov 6, 2019

I think there is a bug when using DeferredValue together with Action.sequence. If one of the sequenced Actions have a deferred child field queries will timeout. The below code reproduces this issue. query1 works but query2 will timeout because we query for the deferred field bar.

import sangria.execution.Executor
import sangria.execution.deferred.{Fetcher, HasId}
import sangria.macros.derive.{GraphQLField, deriveObjectType, deriveContextObjectType}
import sangria.marshalling.playJson.PlayJsonResultMarshaller
import sangria.marshalling.playJson.PlayJsonInputUnmarshallerJObject
import sangria.parser.QueryParser
import sangria.schema.{Action, DeferredValue, ObjectType, Schema}

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
object Example extends App {

  case class Query() {
    @GraphQLField
    def foos: Action[Unit, Seq[Foo]] = Action.sequence[Unit, Foo](Seq(Foo("foo")))
  }

  object Query {
    val queryType = deriveContextObjectType[Unit, Query, Any](_ => Query())
  }

  case class Foo(id: String) {
    @GraphQLField
    def bar: DeferredValue[Unit, Bar] = Bar.get("bar")
  }

  object Foo {
    implicit val FooType: ObjectType[Unit, Foo] = deriveObjectType[Unit, Foo]()
  }

  case class Bar(id: String)

  object Bar {

    implicit val BarType: ObjectType[Unit, Bar] = deriveObjectType[Unit, Bar]()
    implicit def hasId: HasId[Bar, String] = HasId(_.id)
    val fetcher = Fetcher((_: Unit, ids: Seq[String]) => Future.successful(ids.map(id => Bar(id))))
    def get(id: String): DeferredValue[Unit, Bar] = DeferredValue(fetcher.defer(id))
  }

  val schema: Schema[Unit, Any] = Schema(Query.queryType)

  val query1 = """
                |{
                |  foos {
                |    id
                |  }
                |}
              """.stripMargin

  val query2 = """
                 |{
                 |  foos {
                 |    bar {
                 |      id
                 |    }
                 |  }
                 |}
               """.stripMargin

  println(Await.result(Executor.execute(schema = schema, queryAst = QueryParser.parse(query1).get), 10 seconds)) // {"data":{"foos":[{"id":"foo"}]}}

  println(Await.result(Executor.execute(schema = schema, queryAst = QueryParser.parse(query2).get), 10 seconds)) // java.util.concurrent.TimeoutException: Futures timed out after [10 seconds]

}
@danestig
Copy link
Author

danestig commented Nov 8, 2019

I'm woking on this but would appreciate some help. I've tracked the issue to this place (I think)
https://github.com/sangria-graphql/sangria/blob/master/src/main/scala/sangria/execution/Resolver.scala#L311

resolveValue returns the correct deferred values but it seems to me like resolveDctx is not handing deferred values from child fields correct.

If I call processFinalResolve before resolveDctx the query will complete instead of timing out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant