Quarkus: Error in context propagation tutorial

Created on 10 Feb 2020  路  29Comments  路  Source: quarkusio/quarkus

Describe the bug
Unexpected behaviour when I try to use code from Usage example for CompletionStage

Expected behavior
Store persons to Postgre.

Actual behavior
Compile exception. Need to change CompletionStage<Person> => CompletionStage<List<Person>>

Getting error:
gist-link
RESTEASY002020: Unhandled asynchronous exception, sending back 500: java.lang.IllegalStateException: You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO thread will cause major performance issues with your application. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread.

To Reproduce
Steps to reproduce the behavior:

  1. use code from tutorial
  2. mvn clean quarkus:dev

Screenshots
(If applicable, add screenshots to help explain your problem.)

Environment (please complete the following information):

  • Output of uname -a or ver: Darwin MacBook-Pro-Sergey.local 18.7.0 Darwin Kernel Version 18.7.0: Sun Dec 1 18:59:03 PST 2019; root:xnu-4903.278.19~1/RELEASE_X86_64 x86_64
  • Output of java -version: OpenJDK Runtime Environment GraalVM CE 19.3.1 (build 11.0.6+9-jvmci-19.3-b07)
    OpenJDK 64-Bit Server VM GraalVM CE 19.3.1 (build 11.0.6+9-jvmci-19.3-b07, mixed mode, sharing)
  • GraalVM version (if different from Java): GraalVM CE 19.3.1
  • Quarkus version or git rev: 1.2.0.Final
kinbug

All 29 comments

@shvyrev nice catch, mind providing a PR with this fix? Here is the Asciidoc file: https://github.com/quarkusio/quarkus/blob/master/docs/src/main/asciidoc/context-propagation.adoc#usage-example-for-completionstage

Thank you for your trust. Give me some time.

@shvyrev nice catch, mind providing a PR with this fix? Here is the Asciidoc file: https://github.com/quarkusio/quarkus/blob/master/docs/src/main/asciidoc/context-propagation.adoc#usage-example-for-completionstage

Create repo for this bug fix. link

But. And get new error.

Sorry it's very difficult for me. I think this tutorial code never worked fine.
So many errors.

I got new one.

`10:28:28,308 INFO [org.jbo.threads] JBoss Threads version 3.0.0.Final
10:28:29,089 INFO [org.hib.jpa.boo.int.PersistenceXmlParser] HHH000318: Could not find any META-INF/persistence.xml file in the classpath
10:28:29,255 INFO [org.hib.Version] HHH000412: Hibernate Core {5.4.10.Final}
10:28:29,818 ERROR [io.qua.dev.DevModeMain] Failed to start Quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type sun.jvm.hotspot.debugger.ThreadContext and qualifiers [@Default]
- java member: org.acme.ExampleResource#threadContext
- declared on CLASS bean [types=[org.acme.ExampleResource, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.ExampleResource]
at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:879)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:231)
at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:117)
at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:272)
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.quarkus.deployment.ExtensionLoader$2.execute(ExtensionLoader.java:915)
at io.quarkus.builder.BuildContext.run(BuildContext.java:279)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
at java.base/java.lang.Thread.run(Thread.java:834)
at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type sun.jvm.hotspot.debugger.ThreadContext and qualifiers [@Default]
- java member: org.acme.ExampleResource#threadContext
- declared on CLASS bean [types=[org.acme.ExampleResource, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.ExampleResource]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:472)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:416)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:223)
... 14 more

at io.quarkus.runner.RuntimeRunner.run(RuntimeRunner.java:181)
at io.quarkus.dev.DevModeMain.doStart(DevModeMain.java:178)
at io.quarkus.dev.DevModeMain.start(DevModeMain.java:96)
at io.quarkus.dev.DevModeMain.main(DevModeMain.java:67)

Caused by: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type sun.jvm.hotspot.debugger.ThreadContext and qualifiers [@Default]
- java member: org.acme.ExampleResource#threadContext
- declared on CLASS bean [types=[org.acme.ExampleResource, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.ExampleResource]
at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:879)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:231)
at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:117)
at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:272)
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.quarkus.deployment.ExtensionLoader$2.execute(ExtensionLoader.java:915)
at io.quarkus.builder.BuildContext.run(BuildContext.java:279)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
at java.base/java.lang.Thread.run(Thread.java:834)
at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type sun.jvm.hotspot.debugger.ThreadContext and qualifiers [@Default]
- java member: org.acme.ExampleResource#threadContext
- declared on CLASS bean [types=[org.acme.ExampleResource, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.ExampleResource]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:472)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:416)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:223)
... 14 more

at io.quarkus.builder.Execution.run(Execution.java:108)
at io.quarkus.builder.BuildExecutionBuilder.execute(BuildExecutionBuilder.java:79)
at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:128)
at io.quarkus.runner.RuntimeRunner.run(RuntimeRunner.java:114)
... 3 more

Caused by: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type sun.jvm.hotspot.debugger.ThreadContext and qualifiers [@Default]
- java member: org.acme.ExampleResource#threadContext
- declared on CLASS bean [types=[org.acme.ExampleResource, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.ExampleResource]
at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:879)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:231)
at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:117)
at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:272)
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.quarkus.deployment.ExtensionLoader$2.execute(ExtensionLoader.java:915)
at io.quarkus.builder.BuildContext.run(BuildContext.java:279)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
at java.base/java.lang.Thread.run(Thread.java:834)
at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type sun.jvm.hotspot.debugger.ThreadContext and qualifiers [@Default]
- java member: org.acme.ExampleResource#threadContext
- declared on CLASS bean [types=[org.acme.ExampleResource, java.lang.Object], qualifiers=[@Default, @Any], target=org.acme.ExampleResource]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:472)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:416)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:223)
... 14 more

10:28:29,834 INFO [io.qua.dev.DevModeMain] Attempting to start hot replacement endpoint to recover from previous Quarkus startup failure
10:28:29,863 ERROR [io.qua.dev.DevModeMain] Failed to start quarkus: java.lang.IllegalArgumentException: workerPoolSize must be > 0
at io.vertx.core.VertxOptions.setWorkerPoolSize(VertxOptions.java:275)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder.convertToVertxOptions(VertxCoreRecorder.java:152)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder.initializeWeb(VertxCoreRecorder.java:105)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder.startServerAfterFailedStart(VertxHttpRecorder.java:119)
at io.quarkus.vertx.http.deployment.devmode.VertxHotReplacementSetup.handleFailedInitialStart(VertxHotReplacementSetup.java:30)
at io.quarkus.dev.RuntimeUpdatesProcessor.startupFailed(RuntimeUpdatesProcessor.java:452)
at io.quarkus.dev.DevModeMain.doStart(DevModeMain.java:192)
at io.quarkus.dev.DevModeMain.start(DevModeMain.java:96)
at io.quarkus.dev.DevModeMain.main(DevModeMain.java:67)
`

Sorry it's very difficult for me. I think this tutorial code never worked fine.

Don't worry, take your time and help us understand what's wrong in the tutorial so we can fix properly. I think in your case you're importing the wrong class (sun.jvm.hotspot.debugger.ThreadContext instead of org.eclipse.microprofile.context.ThreadContext)

Thank you. You are right. It was my mistake. Used wrong import class.

Help me please.

Added two version of GET request "/people"

  1. Version with ThreadContext (tutorial code).
  • code
  • request http "localhost:8080/hello/v1/people"
  • exception "java.lang.IllegalStateException: You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO thread will cause major performance issues with your application. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread." gist link
  1. Version with ManagedExecutor.
  2. code
  3. request http "localhost:8080/hello/v2/people"
  4. exception "javax.enterprise.context.ContextNotActiveException: interface javax.enterprise.context.RequestScoped" gist link

Can you add the missing files in the root of your https://github.com/shvyrev/quarkus-tutorial-bugfix/ repository? I cannot build it because It's missing the pom.xml

Added pom file to repo.

As I can see from tutorial, I have to add only this dependency.
Added, and getting error.

Please try again.

Thank you.

@manovotn @FroMage can any of you guys look into this one?

Sorry I'm on a super urgent fix today and will be away next week. I can look after that if nobody has time before.

Thank you, @FroMage.

I'm waiting.

So what exception are you getting now and what do I need to do to get there?
Because just grabbing your repo and doing mvn clean install gives me an error from hibernate javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory

@manovotn Yes. U a right. For using Hibernate/Panache u have to use SQL storage. Like Postgre, or MySQL.
In Quarkus U can use application.properties for it. Pls see this link

@FroMage Tell me please, are you still busy?
We need your help.

@manovotn
First of all, I recommend to read messages history. Errors remained the same.
After you finish connecting to database, please check requests "${HOST}/hello/v1/people" and "${HOST}/hello/v2/people".
And u will get this errors.

@gastaldi

Good evening.

I see that PR is 20 days old.
Maybe of course I'm doing something wrong. I'm just a man, I tend to make mistakes. But code was copied from tutorial. I'm sorry, but I have't enough skills to resolve PR myself.

Just write please, what else can I help. Now you are connected to PR contributor who asks me how to connect database. Maybe there is someone else who could help?

Thank you.

@shvyrev hi!

I can confirm that the snippet in the tutorial is definitely wrong, I'll provide a PR fixing it.

About your application, I see the following when hitting http://localhost:8080/hello/v1/people:

2020-03-02 10:24:18,637 ERROR [org.jbo.res.res.i18n] (vert.x-eventloop-thread-2) RESTEASY002020: Unhandled asynchronous exception, sending back 500: java.lang.IllegalStateException: You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO thread will cause major performance issues with your application. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread.
    at io.quarkus.hibernate.orm.runtime.entitymanager.TransactionScopedEntityManager.checkBlocking(TransactionScopedEntityManager.java:83)
    at io.quarkus.hibernate.orm.runtime.entitymanager.TransactionScopedEntityManager.persist(TransactionScopedEntityManager.java:107)
    at io.quarkus.hibernate.orm.runtime.entitymanager.ForwardingEntityManager.persist(ForwardingEntityManager.java:27)
    at io.quarkus.hibernate.orm.panache.runtime.JpaOperations.persist(JpaOperations.java:34)
    at io.quarkus.hibernate.orm.panache.runtime.JpaOperations.persist(JpaOperations.java:29)
    at io.quarkus.hibernate.orm.panache.PanacheEntityBase.persist(PanacheEntityBase.java:43)
    at org.acme.ExampleResource.lambda$firstVersionPeople$0(ExampleResource.java:73)
    at io.smallrye.context.SmallRyeThreadContext$ContextualFunction.apply(SmallRyeThreadContext.java:77)
    at java.util.concurrent.CompletableFuture.uniApply(CompletableFuture.java:616)
    at java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:591)
    at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:488)
    at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1975)
    at io.vertx.axle.AsyncResultCompletionStage.lambda$toCompletionStage$0(AsyncResultCompletionStage.java:18)
    at io.vertx.axle.ext.web.client.HttpRequest$9.handle(HttpRequest.java:598)
    at io.vertx.axle.ext.web.client.HttpRequest$9.handle(HttpRequest.java:595)
    at io.vertx.ext.web.client.impl.HttpContext.handleDispatchResponse(HttpContext.java:308)
    at io.vertx.ext.web.client.impl.HttpContext.execute(HttpContext.java:295)
    at io.vertx.ext.web.client.impl.HttpContext.next(HttpContext.java:270)
    at io.vertx.ext.web.client.impl.predicate.PredicateInterceptor.handle(PredicateInterceptor.java:69)
    at io.vertx.ext.web.client.impl.predicate.PredicateInterceptor.handle(PredicateInterceptor.java:32)
    at io.vertx.ext.web.client.impl.HttpContext.next(HttpContext.java:267)
    at io.vertx.ext.web.client.impl.HttpContext.fire(HttpContext.java:277)
    at io.vertx.ext.web.client.impl.HttpContext.dispatchResponse(HttpContext.java:238)
    at io.vertx.ext.web.client.impl.HttpContext.lambda$null$2(HttpContext.java:367)
    at io.vertx.core.impl.ContextImpl.executeTask(ContextImpl.java:369)
    at io.vertx.core.impl.EventLoopContext.lambda$executeAsync$0(EventLoopContext.java:38)
    at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:497)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)

I also changed to H2 since I didn't want to boot up a PostgreSQL server before testing it.

Since my context propagation know-how is not so good, I'd prefer if @FroMage or someone more experienced in this topic could investigate.

Hah. That's new.

I guess you have to do the JPA calls on worker threads now. You can get there by using ManagedExecutor to capture the contexts and use the *Async methods to get executed on the Quarkus worker thread pool.

Yes,

Use:

@Inject ManagedExecutor executor;

//...
   .thenApplyAsync(..., executor);

Don't need to pass the executor. It has methods for wrapping CS and it sets the default executor to the quarkus one.

@FroMage What about this one ?

Specially made two methods with threadContext and with managedExecutor.
Both return different errors.

@cescoffier Thank you. I'll try this solution.

Update code with
`@Inject ManagedExecutor executor;

//...
.thenApplyAsync(..., executor);`
Updated code.

But getting ContextNotActiveException: interface javax.enterprise.context.RequestScoped error

Add @ActivateRequestContext
But still getting error.

Try:

    @Transactional
    @GET
    @Path("/v1/people")
    public CompletionStage<List<Person>> firstVersionPeople() throws SystemException {
        // Create a REST client to the Star Wars API
        WebClient client = WebClient.create(vertx,
                new WebClientOptions()
                        .setDefaultHost("swapi.co")
                        .setDefaultPort(443)
                        .setSsl(true));

        // get the list of Star Wars people, with context capture
        return threadContext.withContextCapture(client.get("/api/people/").send())
                .thenApplyAsync(response -> {
                    JsonObject json = response.bodyAsJsonObject();
                    List<Person> persons = new ArrayList<>(json.getInteger("count"));
                    // Store them in the DB
                    // Note that we're still in the same transaction as the outer method
                    for (Object element : json.getJsonArray("results")) {
                        Person person = new Person();
                        person.name = ((JsonObject) element).getString("name");
                        person.persist();
                        persons.add(person);
                    }
                    return persons;
                }, managedExecutor);
    }

Also add the following dependency to avoid JAX-RS errors with ArrayList:

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jackson</artifactId>
    </dependency>

I fixed the tutorial in https://github.com/quarkusio/quarkus/pull/7517, I'd appreciate any feedback.

Thanks!

@gastaldi Thank you, so much!

@gastaldi Thank you, so much!

Was this page helpful?
0 / 5 - 0 ratings