Search code examples
javareactive-programmingquarkusvert.xmutiny

The current operation requires a safe (isolated) Vert.x sub-context, but the current context hasn't been flagged as such


I am using Quarkus version 2.11.1.Final. With the following `io.quarkus dependencies:

  1. smallrye-mutiny-vertx-web-client
  2. quarkus-resteasy-reactive
  3. quarkus-hibernate-reactive

In a long rest process, I am trying to persist several entities but I get the following error while doing one of the validations.

The current operation requires a safe (isolated) Vert.x sub-context, but the current context hasn't been flagged as such.
You can still use Hibernate Reactive, you just need to avoid using the methods which implicitly require accessing the stateful context, such as MutinySessionFactory#withTransaction and #withSession.

In order to persist a Collection of entities I am using:

@Inject
Mutiny.SessionFactory sf;

public Uni<List<T>> createAll(List<T> t) {
  if (LOGGER.isDebugEnabled()) {
    LOGGER.debug("#createAll(T)...  {}", t);
  }
    
  return sf.withTransaction(
      (s, t) -> s.persistAll((Object[]) t.toArray(new T[0]))
          .replaceWith(t));
}

I have already try to change the previous return to:


return sf.withStatelessTransaction((s, t) ->s.insertAll((Object[]) t.toArray(new T[0]))
    .replaceWith(t));

But I still getting the same error. Anyone knows how can I handle the vertx context inside Quarkus or anyway of persisting the entities without getting this error?


Solution

  • Hibernate Reactive does NOT work even if you duplicate the context for calling sf.withTrasaction.

    So the only feasible way to make it work is by manually marking the context as safe with the function io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle.setContextSafe

    import io.vertx.core.Vertx;
    import io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle;
    
    ...
    
    public final class MyClass {
    
      @Inject
      private Vertx vertx;
    
      @Inject
      private RepoT repoT;
    
      public Uni<Void> cleanContext() {
        final io.vertx.core.Context newContext = vertx.getOrCreateContext();
        VertxContextSafetyToggle.setContextSafe(newContext, true);
        return Uni.createFrom().voidItem();
      }
    
      public Uni<T> create(T t) {
    
        return this.cleanContext()
            .flatMap( repoT.createAll(t) ) // Method which call hibernate
            ...
    }