Hibernate-reactive: openSession() return error "This needs to be run on the Vert.x event loop"

Created on 12 May 2021  ·  7Comments  ·  Source: hibernate/hibernate-reactive

Hi,

till now Vertx was simply hidden from me while using Hibernate reactive API (1.0.0.CR4). But I have to expose an API to return a session that will be kept open until the client that use this API will decide to close it.
I'm running a Junit test, and I have the following API :

    public Stage.Session openSession() throws ExecutionException, InterruptedException {
        if (session != null && session.isOpen()) {
            session.close();
        }
        Stage.Session newSession = sessionFactory.openSession();
        this.session = newSession;
        return newSession ;
   }

And in my junit test:
Stage.Session session = deviceRepository.openSession();
When I run the code I got the error:
This needs to be run on the Vert.x event loop
I tried to refactor the code in many different way but I didn't succeed to make it running.

Can you please give me your recommendation how to do it correctly ?

Thanks.

Most helpful comment

Yes, I will

All 7 comments

Hi,
the problem with the session is that it's not thread-safe, using it in different threads may cause issues that are hard to debug. Also, when a new session is created is bound to a Vert.x context and needs to be used in the same context after that.

This is normally taken care of by Hibernate Reactive when one uses the SessionFactory#withTransaction and SessionFactory#withSession.

Your tests aren't working because they run in a JUnit thread, and not a Vert.x one.
One way to solve this issue in JUnit 4 is via a rule included in the library io.vertx:vertx-unit:4.0.3:

@Rule
public RunTestOnContext vertxContextRule = new RunTestOnContext();

This will make sure that your tests run in a Vert.x context.

This is not enough though, you also need to make sure that the session is bound to the same Vert.x context defined by the rule.

VertxInstance service:

In general, the way to achieve this is by creating a custom VertxInstance service.

This service tells Hibernate Reactive how to get the correct Vert.x Instance to use when the session is created.
If you create the SessionFactory programmatically, here's an example on how you can do it:

Configuration configuration = new Configuration();
StandardServiceRegistryBuilder builder = new ReactiveServiceRegistryBuilder()
                .addService( VertxInstance.class, (VertxInstance) () -> getMyVertxInstance())
                .applySettings( configuration.getProperties() );
StandardServiceRegistry registry = builder.build();
SessionFactory sessionFactory = configuration.buildSessionFactory( registry );

Alternatively, you can define it using the ServiceLoader mechanism of the JDK:

  1. Add a text file named org.hibernate.reactive.vertx.VertxInstance under
    /META-INF/services/
  2. The text file will contain the path to the class implementing the VertxInstance interface:
    org.myproject.MyVertxProvider

Now Hibernate Reactive will call an instance of MyVertxProvider when in need of a Vert.x instance and if your code runs in the same Vert.x context, everything should work.

Fixing the issue with JUnit 4:

Getting back to the tests, one way to fix them would be:

@Rule
public RunTestOnContext vertxContextRule = new RunTestOnContext();

...

Configuration configuration = new Configuration();
StandardServiceRegistryBuilder builder = new ReactiveServiceRegistryBuilder()
                .addService( VertxInstance.class, (VertxInstance) () -> vertxContextRule.vertx() )
                .applySettings( configuration.getProperties() );
SessionFactory sessionFactory = configuration.buildSessionFactory(  builder.build() );

If you are not using the rule, you can run code in a specific Vert.x context in the following way:

Context currentContext = Vertx.currentContext();
currentContext.runOnContext( event -> {
   // Here you should be able to use the session
});

You should add what you just wrote as a FAQ to the website or wherever.

Yes, I will

@DavideD Very appreciate your explanation. Thanks.

I've created an issue for keeping track of these changes to the documentation/website: https://github.com/hibernate/hibernate-reactive/issues/751

I'm going to close this issue. Feel free to ask more questions is something else is not clear.

Thank you.

@DavideD Is it possible to use the following code you mentioned earlier with JUnit 5?

Context currentContext = Vertx.currentContext();
currentContext.runOnContext( event -> {
   // Here you should be able to use the session
});

Yes, that code is Vert.x, not JUnit.

But there is not an equivalent extension for JUnit 5 of:

@Rule
public RunTestOnContext vertxContextRule = new RunTestOnContext();
Was this page helpful?
0 / 5 - 0 ratings