For everyone who has this problem and uses Quarkus 3 with Vertx bare Api.
I fix this error by forcing the JDBC Call to the Vertx Eventbus thread by wrapping it in a EvenBus Consuming function as described in the official documentation, and fiddling around with @WithTransaction, @WithSession, @WithSessionOnDemand or Panache.withTransaction{}.
This results in code which I'm sure gives me cancer in the long run, as the revenge of karma and the coding gods. But hey, it's temporary code as I migrate my vertx code to mainly quarkus with sparkles of vertx.
fun createToken(userId: String): Future<String> {
val promise = Promise.promise<String>()
eventBus.request<String>("createTokenMsg", userId)
.onSuccess { msg -> promise.complete(msg.body()) }
.onFailure(promise::fail)
return promise.future()
}
@ConsumeEvent("createTokenMsg")
fun createTokenMsgConsume(msg: Message<String>) {
val userId = msg.body()
createToken(userId).subscribe().with(
{ msg.reply(it.token) },
{ error: Throwable ->
val txt = "Fail to create token for user id $userId"
logger.log(Level.SEVERE, txt, error)
msg.fail(500, txt)
}
)
}
@WithSession
fun createToken(userId: String): Uni<TokenIdEntity> {
return Panache
.withTransaction { repository.findByUserId(userId) }
.chain { found: TokenIdEntity? ->
val token = found ?: TokenIdEntity(userId = userId)
token.regenrateToken()
Panache.withTransaction { repository.persistAndFlush(token) }
}
}
You can use it with Objects to, you hate to use the JsonObject
Not an ideal solution because:
- You misuse the eventbus for something which should be a function call (which introduce a lot of overhead)
- If your code runs in a vertx cluster, it may be consumed by another instance
- You loose your stacktrace at this point, you can log the .onFailure method of the eventbus.request-Future but the trace is lost at this point. (which sucks big time for debugging)
Disclaimer
I am not a very experienced user of Hibernate-Reactive, Panache and Quarkus so maybe this solution is shooting a sparrow with a shotgun , where you miss all of your 7 rounds and the bird dies of old age, but it works for me at a point where the other answers , were not descriptive enough or does not work.
The @Transactional solution does not work for me because quarkus takes an issue to call JTA transactions from an io Thread
io.quarkus.runtime.BlockingOperationNotAllowedException: Cannot start a JTA transaction from the IO thread.
But I'm curious about better solutions and hope that my solution maybe leads in a direction for a better solution.