Hibernate-reactive: openSession () devuelve el error "Esto debe ejecutarse en el bucle de eventos Vert.x"

Creado en 12 may. 2021  ·  7Comentarios  ·  Fuente: hibernate/hibernate-reactive

Hola,

hasta ahora, Vertx simplemente estaba oculto para mí mientras usaba la API reactiva de Hibernate (1.0.0.CR4). Pero tengo que exponer una API para devolver una sesión que se mantendrá abierta hasta que el cliente que usa esta API decida cerrarla.
Estoy ejecutando una prueba de Junit y tengo la siguiente 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 ;
   }

Y en mi prueba junit:
Stage.Session session = deviceRepository.openSession();
Cuando ejecuto el código, aparece el error:
This needs to be run on the Vert.x event loop
Intenté refactorizar el código de muchas formas diferentes, pero no logré hacerlo funcionar.

¿Puede darme su recomendación sobre cómo hacerlo correctamente?

Gracias.

Comentario más útil

Sí, lo haré

Todos 7 comentarios

Hola,
El problema con la sesión es que no es seguro para subprocesos, su uso en diferentes subprocesos puede causar problemas que son difíciles de depurar. Además, cuando se crea una nueva sesión, está vinculada a un contexto Vert.x y debe usarse en el mismo contexto después de eso.

Esto normalmente lo soluciona Hibernate Reactive cuando se usan SessionFactory#withTransaction y SessionFactory#withSession .

Tus pruebas no funcionan porque se ejecutan en un hilo JUnit y no en uno Vert.x.
Una forma de resolver este problema en JUnit 4 es mediante una regla incluida en la biblioteca io.vertx:vertx-unit:4.0.3 :

<strong i="13">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();

Esto asegurará que sus pruebas se ejecuten en un contexto Vert.x.

Sin embargo, esto no es suficiente, también debe asegurarse de que la sesión esté vinculada al mismo contexto Vert.x definido por la regla.

Servicio VertxInstance:

En general, la forma de lograrlo es creando un servicio VertxInstance personalizado.

Este servicio le dice a Hibernate Reactive cómo obtener la Instancia Vert.x correcta para usar cuando se crea la sesión.
Si crea SessionFactory mediante programación, aquí hay un ejemplo de cómo puede hacerlo:

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 );

Alternativamente, puede definirlo utilizando el mecanismo ServiceLoader del JDK :

  1. Agregue un archivo de texto llamado org.hibernate.reactive.vertx.VertxInstance debajo
    /META-INF/services/
  2. El archivo de texto contendrá la ruta a la clase que implementa la interfaz VertxInstance :
    org.myproject.MyVertxProvider

Ahora Hibernate Reactive llamará a una instancia de MyVertxProvider cuando necesite una instancia de Vert.x y si su código se ejecuta en el mismo contexto de Vert.x, todo debería funcionar.

Solucionando el problema con JUnit 4:

Volviendo a las pruebas, una forma de corregirlas sería:

<strong i="41">@Rule</strong>
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() );

Si no está utilizando la regla, puede ejecutar código en un contexto Vert.x específico de la siguiente manera:

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

Debe agregar lo que acaba de escribir como una pregunta frecuente en el sitio web o donde sea.

Sí, lo haré

@DavideD Agradezco mucho tu explicación. Gracias.

Creé un problema para realizar un seguimiento de estos cambios en la documentación / sitio web: https://github.com/hibernate/hibernate-reactive/issues/751

Voy a cerrar este tema. Siéntase libre de hacer más preguntas, hay algo más que no está claro.

Gracias.

@DavideD ¿Es posible usar el siguiente código que mencionaste anteriormente con JUnit 5?

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

Sí, ese código es Vert.x, no JUnit.

Pero no hay una extensión equivalente para JUnit 5 de:

<strong i="8">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
¿Fue útil esta página
0 / 5 - 0 calificaciones