quarkus: @RunOnVirtualThread cannot be used in override methods

Describe the bug

Inside a Quarkus 3.4.1 application, I cannot log virtual threads to verify virtual threads usage for a simple demo, using @RunOnVirtualThread. I am running the app with /Library/Java/JavaVirtualMachines/corretto-19.0.2/Contents/Home/bin/java (Java 19) Inside maven-compiler-plugin I have this configuration

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${compiler-plugin.version}</version>
    <configuration>
        <compilerArgs>
            <arg>--enable-preview</arg>
            <arg>-parameters</arg>
        </compilerArgs>
    </configuration>
</plugin>

Like said inside https://quarkus.io/guides/virtual-threads#terminology guide.

I have

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

These log properties

# Log
quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{2.}] %h %H ${quarkus.http.port} %i (%t) %s%e%n
quarkus.log.console.level=INFO
quarkus.log.file.enable=false
#quarkus.log.file.path=/tmp/bile.log
quarkus.log.file.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{2.}] %h %H ${quarkus.http.port} %i (%t) %s%e%n

With this configuration I would like to log if a method is running with virtual threads with quarkus-virtual-thread- prefix, but when I run a REST call to method annotated with @RunOnVirtualThread, it doesn’t log virtual threads. The method is

@Override
    @RunOnVirtualThread
    public Response reactive() {
        log.info("operationName=reactive");
        // Runs on the event loop
        return Response.ok(Map.of("msg", Thread.currentThread())).build();
    }

How can I verify that actual virtual threads is running?

Expected behavior

I’m expecting like this

2023-09-25 22:48:13,539 INFO  [it.gd.bo.MyApiImpl] lorenzos-macbook-pro lorenzos-macbook-pro.local 8083 15051 (executor-quarkus-virtual-thread-5) operationName=reactive

or something like this to verify actual virtual threads instead platform threads

Actual behavior

Actual log is

2023-09-25 22:48:13,539 INFO  [it.gd.bo.MyApiImpl] lorenzos-macbook-pro lorenzos-macbook-pro.local 8083 15051 (executor-thread-5) operationName=reactive

How to Reproduce?

No response

Output of uname -a or ver

Darwin Lorenzos-MacBook-Pro.local 22.3.0 Darwin Kernel Version 22.3.0: Mon Jan 30 20:39:46 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6020 arm64

Output of java -version

java 19

GraalVM version (if different from Java)

No response

Quarkus version or git rev

3.4.1

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

My laptop is MacOs with ARM architecture:

Darwin Lorenzos-MacBook-Pro.local 22.3.0 Darwin Kernel Version 22.3.0: Mon Jan 30 20:39:46 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6020 arm64

Configuration of app

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>it.gdgpt</groupId>
  <artifactId>virtual-kafka-streams</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <properties>
    <compiler-plugin.version>3.10.1</compiler-plugin.version>
    <maven.compiler.source>19</maven.compiler.source>
    <maven.compiler.target>19</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
    <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
    <quarkus.platform.version>3.4.1</quarkus.platform.version>
    <skipITs>true</skipITs>
    <surefire-plugin.version>3.0.0-M7</surefire-plugin.version>
    <npg-be-ark-library.version>0.0.2-java-1.8-SNAPSHOT</npg-be-ark-library.version>
  </properties>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>${quarkus.platform.group-id}</groupId>
        <artifactId>${quarkus.platform.artifact-id}</artifactId>
        <version>${quarkus.platform.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <modules>
    <module>virtual-kafka-streams-liquibase</module>
    <module>virtual-kafka-streams-application</module>
  </modules>
</project>

<?xml version="1.0" encoding="UTF-8"?>
        <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>it.gdgpt</groupId>
        <artifactId>virtual-kafka-streams</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>

    <artifactId>virtual-kafka-streams-application</artifactId>
    <version>1.0.0-SNAPSHOT</version>

    <dependencies>
<!--        <dependency>-->
<!--            <groupId>io.quarkus</groupId>-->
<!--            <artifactId>quarkus-smallrye-reactive-messaging-kafka</artifactId>-->
<!--        </dependency>-->
<!--        <dependency>-->
<!--            <groupId>io.quarkus</groupId>-->
<!--            <artifactId>quarkus-kafka-streams</artifactId>-->
<!--        </dependency>-->
        <dependency>
            <groupId>io.vavr</groupId>
            <artifactId>vavr</artifactId>
            <version>0.10.4</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-hibernate-orm</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-rest-client-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-openapi</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-scheduler</artifactId>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>io.quarkus</groupId>-->
<!--            <artifactId>quarkus-resteasy-jackson</artifactId>-->
<!--        </dependency>-->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-health</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-jdbc-postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-jdbc-h2</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-arc</artifactId>
        </dependency>
<!--        <dependency>-->
<!--            <groupId>io.quarkus</groupId>-->
<!--            <artifactId>quarkus-resteasy</artifactId>-->
<!--        </dependency>-->
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.rest-assured</groupId>
            <artifactId>rest-assured</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>${quarkus.platform.version}</version>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                            <goal>generate-code</goal>
                            <goal>generate-code-tests</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${compiler-plugin.version}</version>
                <configuration>
                    <compilerArgs>
                        <arg>--enable-preview</arg>
                        <arg>-parameters</arg>
                    </compilerArgs>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <configuration>
                    <systemPropertyVariables>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                        <configuration>
                            <systemPropertyVariables>
                                <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
                                <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                                <maven.home>${maven.home}</maven.home>
                            </systemPropertyVariables>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>19</source>
                    <target>19</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <profiles>
        <profile>
            <id>native</id>
            <activation>
                <property>
                    <name>native</name>
                </property>
            </activation>
            <properties>
                <skipITs>false</skipITs>
                <quarkus.package.type>native</quarkus.package.type>
            </properties>
        </profile>
    </profiles>

</project>

About this issue

  • Original URL
  • State: open
  • Created 9 months ago
  • Comments: 15 (11 by maintainers)

Most upvoted comments

A possible workaround is given by the following statement from the Jakarta REST specification:

For consistency with other Jakarta EE specifications, it is recommended to always repeat annotations instead of relying on annotation inheritance.

You can just copy the JAX-RS annotations from the interface to the resource method and then add @RunOnVirtualThread.

@Ladicek I’m going to test this workaround, thanks!

How annotation inheritance in Java works is described here: https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html Notably, annotations are only inherited on classes (not on fields or methods), and only from superclasses (not from interfaces).

How annotation inheritance in JAX-RS works is described here: https://jakarta.ee/specifications/restful-ws/3.1/jakarta-restful-ws-spec-3.1#annotationinheritance Notably, it only concerns inheritance of JAX-RS annotations on methods and method parameters. The way I read it, it means that non-JAX-RS annotations are never inherited and should be present on the resource method.

So if I understand the present issue correctly, we have a resource class with a resource method that inherits JAX-RS annotations from an interface method and then adds @RunOnVirtualThread on its own. I think it’s fairly sensible to treat some of our annotations as JAX-RS annotations, but I don’t feel like @RunOnVirtualThread should be one of those. It’s not my call to make, but if you agree with my opinion, what we have here is a genuine bug.