Home > Software engineering >  Using Transaction in PostConstruct
Using Transaction in PostConstruct

Time:07-20

I'm using Hibernate with Panache and I need to add a user when the application starts. For that, I'm annotating my bean with @Startup and then I have a method with the annotation @PostConstruct.

Currently, I'm using the following code:

@Startup
@ApplicationScoped
class AuthService {
    @Inject
    lateinit var userRepository: UserRepository

    @PostConstruct
    fun init() {
        logger.info("Creating admin user")

        val user = User(
            "Admin", ADMIN_NAME, BcryptUtil.bcryptHash(ADMIN_PASS), mutableSetOf(Role.ADMIN)
        )

        Panache.withTransaction {
            userRepository.persist(user)
        }.subscribe().with({
            logger.info("Done")
        }, { fail ->
            logger.error("Failed admin creation: $fail")
        })
    }
}

From what I found, when this method is called there are no guarantees that everything is already set, and I guess that is why it sometimes fails with the error Session/EntityManager is closed. I have already checked this question but since it is for Spring, the method doesn't work and I didn't find anything similar for Quarkus.

Am I missing any solution or is there a better approach to this?

CodePudding user response:

This should work (I wrote it in Java because I'm not familiar with Kotlin):

    @PostConstruct
    public void init() {
        logger.info( "Creating admin user" );

        User user = new User(
            "Admin", ADMIN_NAME, BcryptUtil.bcryptHash(ADMIN_PASS), mutableSetOf(Role.ADMIN)
        );

        Panache
                .withTransaction( () -> userRepository.persist( user ) )
                .onItemOrFailure().invoke( (v, e ) -> {
                        if (e != null) {
                            logger.info( "Done!" );
                        }
                        else {
                            logger.errorf( "Failed admin creation: %s", e );
                        }
                } )
                .await().indefinitely();
    }

Note that this code is not reactive though. The .await().indefinetily() will block the thread until the operation is completed.

The correct approach should be having a method like:

    @PostConstruct
    public Uni<Void> init() {
       ...
       return Panache.withTransaction(...);
    }

But this doesn't work at the moment in Quarkus.

  • Related