Oi,
até agora o Vertx estava simplesmente escondido de mim enquanto usava a API reativa do Hibernate (1.0.0.CR4). Mas eu tenho que expor uma API para retornar uma sessão que será mantida aberta até que o cliente que usa essa API decida fechá-la.
Estou executando um teste Junit e tenho a seguinte 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 ;
}
E no meu teste junit:
Stage.Session session = deviceRepository.openSession();
Quando executo o código, recebo o erro:
This needs to be run on the Vert.x event loop
Tentei refatorar o código de muitas maneiras diferentes, mas não consegui colocá-lo em execução.
Você pode me dar sua recomendação de como fazer isso corretamente?
Obrigado.
Oi,
o problema com a sessão é que ela não é segura para threads; usá-la em diferentes threads pode causar problemas difíceis de depurar. Além disso, quando uma nova sessão é criada, ela é vinculada a um contexto Vert.x e precisa ser usada no mesmo contexto depois disso.
Isso normalmente é feito pelo Hibernate Reactive quando se usa SessionFactory#withTransaction
e SessionFactory#withSession
.
Seus testes não estão funcionando porque são executados em um encadeamento JUnit e não em um Vert.x.
Uma maneira de resolver esse problema no JUnit 4 é por meio de uma regra incluída na biblioteca io.vertx:vertx-unit:4.0.3
:
<strong i="13">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
Isso garantirá que seus testes sejam executados em um contexto Vert.x.
No entanto, isso não é suficiente, você também precisa se certificar de que a sessão está vinculada ao mesmo contexto Vert.x definido pela regra.
Em geral, a maneira de conseguir isso é criando um serviço VertxInstance personalizado.
Este serviço informa ao Hibernate Reactive como obter a instância Vert.x correta para usar quando a sessão for criada.
Se você criar a SessionFactory programaticamente, aqui está um exemplo de como você pode fazer isso:
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 );
Como alternativa, você pode defini-lo usando o mecanismo ServiceLoader do JDK :
org.hibernate.reactive.vertx.VertxInstance
em
/META-INF/services/
VertxInstance
:
org.myproject.MyVertxProvider
Agora o Hibernate Reactive chamará uma instância de MyVertxProvider
quando precisar de uma instância Vert.x e se seu código for executado no mesmo contexto Vert.x, tudo deve funcionar.
Voltando aos testes, uma maneira de corrigi-los seria:
<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() );
Se você não estiver usando a regra, poderá executar o código em um contexto Vert.x específico da seguinte maneira:
Context currentContext = Vertx.currentContext();
currentContext.runOnContext( event -> {
// Here you should be able to use the session
});
Você deve adicionar o que acabou de escrever como FAQ no site ou em qualquer outro lugar.
Sim, eu vou
@DavideD Agradeço muito sua explicação. Obrigado.
Eu criei um problema para acompanhar essas alterações na documentação / site: https://github.com/hibernate/hibernate-reactive/issues/751
Vou encerrar este problema. Sinta-se à vontade para fazer mais perguntas se outra coisa não estiver clara.
Obrigada.
@DavideD É possível usar o código a seguir que você mencionou anteriormente com o JUnit 5?
Context currentContext = Vertx.currentContext();
currentContext.runOnContext( event -> {
// Here you should be able to use the session
});
Sim, esse código é Vert.x, não JUnit.
Mas não há uma extensão equivalente para JUnit 5 de:
<strong i="8">@Rule</strong>
public RunTestOnContext vertxContextRule = new RunTestOnContext();
Comentários muito úteis
Sim, eu vou