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

GraphQL Batch processing throws a ContextNotActiveException #13385

Closed
funcbro opened this issue Nov 19, 2020 · 13 comments · Fixed by #13736
Closed

GraphQL Batch processing throws a ContextNotActiveException #13385

funcbro opened this issue Nov 19, 2020 · 13 comments · Fixed by #13736
Assignees
Milestone

Comments

@funcbro
Copy link

funcbro commented Nov 19, 2020

Describe the bug
GraphQL Batch processing throws a ContextNotActiveException

Expected behavior
As described in https://quarkus.io/guides/microprofile-graphql#batching Batch processing should work =)

Actual behavior
GraphQL Batch processing throws a ContextNotActiveException

To Reproduce
See attachment for simple setup:
TestGraphQLResource.zip

Simple Source relations like the following work as expected:

    public Yyy getYyy(@Source Xxx xxx) {
        return mapYyy(xxx);
    }

    public List<Zzz> getZzz(@Source Xxx xxx) {
        return mapZzz(xxx);
    }

When changing to Batch processing a ContextNotActiveException is thrown.

    public List<Yyy> getYyy(@Source List<Xxx> xxxList) {
        return xxxList.stream().map(this::mapYyy).collect(Collectors.toList());
    }

    public List<List<Zzz>> getZzz(@Source List<Xxx> xxxList) {
        return xxxList.stream().map(this::mapZzz).collect(Collectors.toList());
    }

Configuration
No properties set for GraphQL

Screenshots

2020-11-19 11:29:59,847 ERROR [io.sma.graphql] (ForkJoinPool.commonPool-worker-13) SRGQL012000: Data Fetching Error: java.util.concurrent.CompletionException: java.lang.RuntimeException: javax.enterprise.context.ContextNotActiveException: interface javax.enterprise.context.RequestScoped
        at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314)
        at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319)
        at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702)
        at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1692)
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: java.lang.RuntimeException: javax.enterprise.context.ContextNotActiveException: interface javax.enterprise.context.RequestScoped
        at io.smallrye.graphql.execution.batchloader.SourceBatchLoader.doSourceCall(SourceBatchLoader.java:83)
        at io.smallrye.graphql.execution.batchloader.SourceBatchLoader.access$000(SourceBatchLoader.java:27)
        at io.smallrye.graphql.execution.batchloader.SourceBatchLoader$1.run(SourceBatchLoader.java:63)
        at java.base/java.security.AccessController.doPrivileged(Native Method)
        at io.smallrye.graphql.execution.batchloader.SourceBatchLoader.invokePrivileged(SourceBatchLoader.java:56)
        at io.smallrye.graphql.execution.batchloader.SourceBatchLoader.lambda$load$0(SourceBatchLoader.java:49)
        at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700)
        ... 6 more
Caused by: javax.enterprise.context.ContextNotActiveException: interface javax.enterprise.context.RequestScoped
        at whatever.wherever.TestGraphQLResource_ClientProxy.arc$delegate(TestGraphQLResource_ClientProxy.zig:68)
        at whatever.wherever.TestGraphQLResource_ClientProxy.getZzz(TestGraphQLResource_ClientProxy.zig:249)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at io.smallrye.graphql.execution.datafetcher.helper.ReflectionHelper.invoke(ReflectionHelper.java:45)
        at io.smallrye.graphql.execution.batchloader.SourceBatchLoader.doSourceCall(SourceBatchLoader.java:80)
        ... 12 more

Environment (please complete the following information):

  • Output of uname -a or ver:
  • Output of java -version:
    openjdk version "11.0.7" 2020-04-14
    OpenJDK Runtime Environment GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02)
    OpenJDK 64-Bit Server VM GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02, mixed mode, sharing)
  • GraalVM version (if different from Java):
  • Quarkus version or git rev: 1.9.2
  • Build tool (ie. output of mvnw --version or gradlew --version): 3.6.3

Additional context
(Add any other context about the problem here.)

@funcbro funcbro added the kind/bug Something isn't working label Nov 19, 2020
@ghost
Copy link

ghost commented Nov 19, 2020

/cc @jmartisk, @phillip-kruger, @sberyozkin

@phillip-kruger
Copy link
Member

Hi @funcbro , thanks for this. We know about this one. Can you test against 1.10.0 and let me know, or alternatively if you have a project example I can look at ?

@funcbro
Copy link
Author

funcbro commented Nov 20, 2020

Hi @phillip-kruger, just tested the problem in 1.10.0.Final. The Exception is still thrown.

Here is the Test-Project based on the 1.10.0.Final archetype:
microprofile-graphql-quickstart.zip

And here is the test-query:

{
  xxx {
    id
    a
    yyyId
    yyy {
      id
      a
    }
    zzzIdList
    zzz {
      id
      a
    }
  }
}

@phillip-kruger
Copy link
Member

Thanks ! I am look at this.

@phillip-kruger
Copy link
Member

phillip-kruger commented Nov 20, 2020

@funcbro For now, remove @RequestScoped and see if that work please. Let me know

@jmartisk
Copy link
Contributor

jmartisk commented Nov 20, 2020

@phillip-kruger just a little hint should you be unsure where to look - https://github.com/quarkusio/quarkus/blob/1.10.0.Final/extensions/smallrye-graphql/runtime/src/main/java/io/quarkus/smallrye/graphql/runtime/SmallRyeGraphQLExecutionHandler.java#L57 this is where we activate the request context. I think the problem with batching is that the handling is performed asynchronously in different threads which don't have the request context active (it didn't go through this piece of code)?
It has nothing to do with the application containing @RequestScoped or not. We have to activate the request scope always.

@phillip-kruger
Copy link
Member

Yes, I just wanted to give @funcbro a "workaround". Do you want to do a fix ?

@jmartisk
Copy link
Contributor

Haven't tried but I think that if the processing is asynchronous then the annotation won't have any effect.
Sure, I can have a look into it.

@jmartisk jmartisk self-assigned this Nov 20, 2020
@funcbro
Copy link
Author

funcbro commented Nov 20, 2020

Removing RequestScoped (even it if worked) is no option in my case. Might work for the test-case though.
Also tried to use ActivateRequestContext annotation which also has no impact

@jmartisk
Copy link
Contributor

Not sure yet how to fix it.
We are processing a request, the request context is active, but during the processing, we spawn a new thread in the ForkJoin pool (see https://github.com/smallrye/smallrye-graphql/blob/1.0.15/server/implementation/src/main/java/io/smallrye/graphql/spi/datafetcher/DefaultDataFetcherService.java#L54) - and that thread accesses CDI beans, so it needs to have the request context propagated into it - how should we do that?
There is the problem that this is happenning in SmallRye code, so we don't have access to Arc.container().requestContext() - do we need to move this code to Quarkus codebase to be able to use Arc and pass the active context to the new thread? Or switch from ForkJoin pool to an executor managed by SR Context Propagation?
Perhaps @mkouba has some clues...

@gsmet
Copy link
Member

gsmet commented Nov 23, 2020

Isn't it what SmallRye Context Propagation is supposed to solve?

@mkouba
Copy link
Contributor

mkouba commented Nov 23, 2020

Well, it's not a Quarkus-only problem. If you spawn a new thread you need to make sure the request context is (a) active or (b) propagated. For (a) you can use e.g. the RequestContextController (portable CDI API). For (b) @gsmet is right and the SmallRye Context Propagation is the way to go.

@jmartisk
Copy link
Contributor

I've started tinkering with the integration of SR Context Propagation into SR GraphQL. Hope to know more next week, it's kind of an uncharted territory for me :)

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

Successfully merging a pull request may close this issue.

5 participants