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.
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.
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 :
org.hibernate.reactive.vertx.VertxInstance
sous
/META-INF/services/
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.
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();
Commentaire le plus utile
Oui