Hi Quarkus team,
during an upgrade to Quarkus 3.38 we ran into a surprising interaction between SmallRye GraphQL and JTA.
From looking at the Quarkus changes, blocking GraphQL resolver methods appear to receive an implicit @Transactional annotation when JTA is available, unless the method/class is already explicitly annotated.
This is probably a good default for many applications, but it can be surprising for resolvers that call code managing JDBC transactions internally. In our case a resolver calls Bucket4j's PostgreSQL proxy manager, which performs its own JDBC transaction handling. After the upgrade, the resolver started running inside JTA and the library failed when trying to handle rollback on an enlisted connection.
The workaround is explicit and reasonable:
@Transactional(Transactional.TxType.NOT_SUPPORTED)
@RunOnVirtualThread
@Query("aiGenerationQuota")
public AiQuota getRemainingQuota() {
...
}
I could not find this behavior documented in the SmallRye GraphQL guide. Would it make sense to add a note that blocking GraphQL resolvers are implicitly transactional when JTA is present, and that @Transactional(TxType.NOT_SUPPORTED) can be used for special opt-out cases?
Thanks!
Hi Quarkus team,
during an upgrade to Quarkus 3.38 we ran into a surprising interaction between SmallRye GraphQL and JTA.
From looking at the Quarkus changes, blocking GraphQL resolver methods appear to receive an implicit
@Transactionalannotation when JTA is available, unless the method/class is already explicitly annotated.This is probably a good default for many applications, but it can be surprising for resolvers that call code managing JDBC transactions internally. In our case a resolver calls Bucket4j's PostgreSQL proxy manager, which performs its own JDBC transaction handling. After the upgrade, the resolver started running inside JTA and the library failed when trying to handle rollback on an enlisted connection.
The workaround is explicit and reasonable:
I could not find this behavior documented in the SmallRye GraphQL guide. Would it make sense to add a note that blocking GraphQL resolvers are implicitly transactional when JTA is present, and that
@Transactional(TxType.NOT_SUPPORTED)can be used for special opt-out cases?Thanks!