Hibernate-reactive: openSession () return error "Isso precisa ser executado no loop de evento Vert.x"

Criado em 12 mai. 2021  ·  7Comentários  ·  Fonte: hibernate/hibernate-reactive

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.

Comentários muito úteis

Sim, eu vou

Todos 7 comentários

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.

Serviço VertxInstance:

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 :

  1. Adicione um arquivo de texto chamado org.hibernate.reactive.vertx.VertxInstance em
    /META-INF/services/
  2. O arquivo de texto conterá o caminho para a classe que implementa a interface 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.

Corrigindo o problema com JUnit 4:

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();
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

gavinking picture gavinking  ·  23Comentários

tsegismont picture tsegismont  ·  20Comentários

DavideD picture DavideD  ·  37Comentários

aguibert picture aguibert  ·  28Comentários

hantsy picture hantsy  ·  7Comentários