Quarkus REST Reactive ServerRequestFilter Has To Be Blocking When Using With Hibernate Panache Reactive
See original GitHub issueI need to write a ServerRequestFilter do some checking by sending request via RestClient. Here is the code:
The RestClient
is reactive:
So in CheckAuthFilter
I use await
and marked the check()
method blocking:
In the document of ServerRequestFilter
, it describes several return types:
I can’t use Uni<RestResponse<Void>>
return type so I can avoid calling .await()
method of Uni
. Because in my web API, I have some hibernate-panache-reactive
code like this:
I have to mark the above method as @Blocking
, and also my ServerRequestFilter
as blocking. If I modify my ServerRequestFilter
to return Uni
, and make my above web method as @NonBlocking
like this:
Then during the runtime, it will throw hibernate related runtime error like this:
From above screenshot I can see the the error is:
java.lang.IllegalStateException: HR000069: Detected use of the reactive Session from a different Thread than the one which was used to open the reactive Session - this suggests an invalid integration; original thread: 'vert.x-eventloop-thread-4' current Thread: 'vert.x-eventloop-thread-8'
Here is the code I changed that could reproduce the above exception:
➤ git diff 10:27:53
diff --git a/src/main/java/cn/alchemystudio/taskserver/auth/CheckAuthFilter.java b/src/main/java/cn/alchemystudio/taskserver/auth/CheckAuthFilter.java
index 4d20b44..84d9466 100644
--- a/src/main/java/cn/alchemystudio/taskserver/auth/CheckAuthFilter.java
+++ b/src/main/java/cn/alchemystudio/taskserver/auth/CheckAuthFilter.java
@@ -4,6 +4,7 @@ import cn.alchemystudio.taskserver.client.HtyucProxy;
import cn.alchemystudio.taskserver.commons.Bag;
import cn.alchemystudio.taskserver.commons.Commons;
import io.smallrye.common.annotation.Blocking;
+import io.smallrye.mutiny.Uni;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.RestResponse;
@@ -30,8 +31,8 @@ public class CheckAuthFilter {
HtyucProxy uc;
@ServerRequestFilter
- @Blocking
- public Optional<RestResponse<Void>> check(ContainerRequestContext ctx) throws Exception {
+// @Blocking
+ public Uni<RestResponse<Void>> check(ContainerRequestContext ctx) throws Exception {
logger.debug(":::CHECK_AUTH_FILTER:::");
logger.debug("CHECK_AUTH_FILTER -> REQUEST_CTX / " + ctx.toString());
@@ -40,7 +41,7 @@ public class CheckAuthFilter {
if (ctx.getHeaderString("HtySudoerToken") == null) {
logger.debug("CHECK_AUTH_FILTER CHECK FAILED -> empty `HtySudoerToken` header");
- return Optional.of(RestResponse.status(Response.Status.FORBIDDEN));
+ return Uni.createFrom().item(RestResponse.status(Response.Status.FORBIDDEN));
}
var tokenStr = ctx.getHeaderString("HtySudoerToken");
@@ -71,7 +72,7 @@ public class CheckAuthFilter {
// }
// );
- return (Optional<RestResponse<Void>>) uc.verifyJwtToken(tokenStr).onItem().transform(
+ return uc.verifyJwtToken(tokenStr).onItem().transform(
resp -> {
var respStr = resp.readEntity(String.class);
logger.debug("CHECK_AUTH_FILTER -> uc.verifyJwtToken RESPONSE / " + respStr);
@@ -80,19 +81,19 @@ public class CheckAuthFilter {
logger.debug("CHECK_AUTH_FILTER CHECK PASSED -> GOOD JWT TOKEN: " + token);
verifyResult.setData(Boolean.TRUE);
verifyOk.setData(true);
- return Optional.empty();
+ return null;
} else {
logger.info("CHECK_AUTH_FILTER CHECK FAILED -> " + token + " RESP / " + respStr);
- return Optional.of(RestResponse.status(Response.Status.FORBIDDEN));
+ return RestResponse.status(Response.Status.FORBIDDEN);
}
}
).onFailure().recoverWithItem(err -> {
logger.debug("CHECK_AUTH_FILTER CHECK FAILED -> ERR: " + err);
- return Optional.of(RestResponse.status(Response.Status.FORBIDDEN));
- }).await().atMost(c.TIMEOUT);
+ return RestResponse.status(Response.Status.FORBIDDEN);
+ });
}
logger.debug("CHECK_AUTH_FILTER -> TOKEN INVAILD / " + tokenStr);
- return Optional.of(RestResponse.status(Response.Status.FORBIDDEN));
+ return Uni.createFrom().item(RestResponse.status(Response.Status.FORBIDDEN));
}
}
\ No newline at end of file
diff --git a/src/main/java/cn/alchemystudio/taskserver/service/TaskServer.java b/src/main/java/cn/alchemystudio/taskserver/service/TaskServer.java
index 1fbbd50..7838707 100644
--- a/src/main/java/cn/alchemystudio/taskserver/service/TaskServer.java
+++ b/src/main/java/cn/alchemystudio/taskserver/service/TaskServer.java
@@ -121,7 +121,7 @@ public class TaskServer {
@GET
@Path("/task_status/{task_id}")
- @Blocking
+// @Blocking
public Uni<Response> task_status(@RestPath String task_id) {
logger.debug("[QUERY_TASK_STATUS] -> " + task_id);
return DbTask.findById(task_id).onItem().transform(task -> {
In conclusion, if I use resteasy-reactive
and hibernate-panache-reactive
together, and in addition I’m using ServerRequestFilter
, then I have to mark both my filter and my web service as @Blocking
, or I will get the reactive Session error thrown by hibernate-panache-reactive
.
I’m not sure whether it is a bug or it is by design, or maybe it’s my usage problem. so I report it here asking for help/suggestions.
Here is the Quarkus version I’m using:
<quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
<quarkus.platform.version>2.2.3.Final</quarkus.platform.version>
Here are the reactive components I’m using:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-reactive-pg-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-reactive-panache</artifactId>
</dependency>
Thanks for reading 😄
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (2 by maintainers)
I think your issue is calling
await
, I think you need to just return aUni<Response>
to keep everything non blocking.I switch from
hibernate-panache-reactive
tohibernate-panache
, and all the transaction related problems are gone. I guess this is the correct way for my usage scenario. Thanks for help!