Search code examples
hibernatequarkus-panachemutinyhibernate-reactive

How to return failure after rollback in Mutiny Pipeline with Panache


Currently learning mutiny and transactions with hibernate-reactive. I need to save Mess Object in database and if there is a specific condition I want to roll back the transaction sending some kind of failure message as return parameter of the save method.

How could I produce Failure or Exception. What would be the best practice in such cases.
Could you please show me an example using this code snippet.

public Uni<Mess> save(Mess mess) {
            return Panache.withTransaction(() -> {
                            if(mess.message.equals("Hello World")){
                                Panache.currentTransaction().invoke(Transaction::markForRollback).subscribe().with(item -> Log.info("Transaction is marked for roll-back"));
                            }
                            return persist(mess);
                            });
        }

Solution

  • It depends if you consider this an exception or not.

    You can create a failed uni using Uni.createFrom().failed(...). So, one way to rewrite your example would be:

    public Uni<Mess> save(Mess mess) {
        return Panache.withTransaction(() -> {
            if (mess.message.equals("Hello World")) {
               return Panache.currentTransaction()
                    .invoke(Mutiny.Transaction::markForRollback)
                    .invoke(() -> Log.info("Transaction is marked for roll-back"))
                    .chain(() -> Uni.createFrom().failure(new RuntimeException()));
            }
            return persist(mess);
        }
    }
    

    If you don't consider this a failure, you can return something else using Uni.createFrom().nullItem() or Uni.createFrom().item(...).

    One thing to keep in mind is that the session should be discarded in case an exception happens while using it. Panache doesn't handle this situation. There is an issue about this and there is a discussion with some workarounds. But, in short, one workaround is to use Hibernate Reactive directly:

    @Inject
    Mutiny.SessionFactory factory;
    
    public Uni<Void> create(Person person){
        return factory.withTransaction( (session, tx) ->  {
             // Now you have a new session and transaction and you can control them any way you want 
        });
    }