Hibernate-reactive: openSession() renvoie l'erreur "Ceci doit être exécuté sur la boucle d'événement Vert.x"

Créé le 12 mai 2021  ·  7Commentaires  ·  Source: hibernate/hibernate-reactive

Salut,

jusqu'à présent, Vertx m'était simplement caché lors de l'utilisation de l'API réactive Hibernate (1.0.0.CR4). Mais je dois exposer une API pour retourner une session qui restera ouverte jusqu'à ce que le client qui utilise cette API décide de la fermer.
J'exécute un test Junit, et j'ai l'API suivante :

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

Et dans mon junit test :
Stage.Session session = deviceRepository.openSession();
Quand j'exécute le code, j'ai l'erreur :
This needs to be run on the Vert.x event loop
J'ai essayé de refactoriser le code de différentes manières mais je n'ai pas réussi à le faire fonctionner.

Pouvez-vous s'il vous plaît me donner votre recommandation comment le faire correctement?

Merci.

Commentaire le plus utile

Oui

Tous les 7 commentaires

Salut,
le problème avec la session est qu'elle n'est pas thread-safe, son utilisation dans différents threads peut entraîner des problèmes difficiles à déboguer. De plus, lorsqu'une nouvelle session est créée, elle est liée à un contexte Vert.x et doit ensuite être utilisée dans le même contexte.

Ceci est normalement pris en charge par Hibernate Reactive lorsque l'on utilise les SessionFactory#withTransaction et SessionFactory#withSession .

Vos tests ne fonctionnent pas car ils s'exécutent dans un thread JUnit et non dans un thread Vert.x.
Une façon de résoudre ce problème dans JUnit 4 consiste à utiliser une règle incluse dans la bibliothèque io.vertx:vertx-unit:4.0.3 :

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

Cela garantira que vos tests s'exécutent dans un contexte Vert.x.

Cela ne suffit pas, vous devez également vous assurer que la session est liée au même contexte Vert.x défini par la règle.

Service VertxInstance :

En général, le moyen d'y parvenir est de créer un service VertxInstance personnalisé.

Ce service indique à Hibernate Reactive comment obtenir la bonne instance Vert.x à utiliser lors de la création de la session.
Si vous créez la SessionFactory par programmation, voici un exemple sur la façon dont vous pouvez le faire :

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

Alternativement, vous pouvez le définir à l'aide du mécanisme ServiceLoader du JDK :

  1. Ajoutez un fichier texte nommé org.hibernate.reactive.vertx.VertxInstance sous
    /META-INF/services/
  2. Le fichier texte contiendra le chemin d'accès à la classe implémentant l'interface VertxInstance :
    org.myproject.MyVertxProvider

Désormais, Hibernate Reactive appellera une instance de MyVertxProvider lorsque vous aurez besoin d'une instance Vert.x et si votre code s'exécute dans le même contexte Vert.x, tout devrait fonctionner.

Correction du problème avec JUnit 4:

Pour en revenir aux tests, une façon de les corriger serait :

<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 vous n'utilisez pas la règle, vous pouvez exécuter du code dans un contexte Vert.x spécifique de la manière suivante :

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

Vous devez ajouter ce que vous venez d'écrire en tant que FAQ sur le site Web ou ailleurs.

Oui

@DavideD Très apprécié votre explication. Merci.

J'ai créé un problème pour garder une trace de ces modifications sur la documentation/le site Web : https://github.com/hibernate/hibernate-reactive/issues/751

Je vais clore ce sujet. N'hésitez pas à poser plus de questions si autre chose n'est pas clair.

Merci.

@DavideD Est-il possible d'utiliser le code suivant que vous avez mentionné plus tôt avec JUnit 5 ?

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

Oui, ce code est Vert.x, pas JUnit.

Mais il ne s'agit pas ici d'une extension équivalente pour JUnit 5 de :

<strong i="8">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

yaakov-berkovitch picture yaakov-berkovitch  ·  16Commentaires

gavinking picture gavinking  ·  6Commentaires

Sanne picture Sanne  ·  12Commentaires

markusdlugi picture markusdlugi  ·  30Commentaires

hantsy picture hantsy  ·  7Commentaires