blocking EntityManager operations

Viewed 1273

I don't want to perform a blocking operation.

Caused by: java.lang.IllegalStateException: You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO thread will cause major performance issues with your application. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread.

Anyone know how to fix this problem? I only have simple operations. a single findAll request that returns 10 rows. I put Tansactional NEVER and I still have the problem. I'm using panache with a simple entity.

   @GET
   @Path("/type")
   @Produces(MediaType.APPLICATION_JSON)
   @Transactional(Transactional.TxType.NEVER)
   public Response get() {
      return AlertType.listAll();
   }
public class AlerteType extends PanacheEntityBase 
{

    @Column(name="ATY_ACTIVE")
    private String active;

    @Column(name="ATY_ID")
    @Id
    private Long oraId;

    @Column(name="ATY_TYPE")
    private String type;
}

thank

3 Answers

"Controller" methods (request / route / path handlers, or whatever you call it) is executed on IO thread and not supposed to do any time consuming tasks such as database querying.
If you're not using reactive database client, try wrap them in side a "Service" class.

@ApplicationScoped
public class AlertService {
    private final AlertType alertType;

    @Inject
    public AlertService(AlertType alertType) {
        this.alertType = alertType;
    }

    public List<Alert> listAll() {
        return this.alertType.listAll();
    }
}

thank you but I already had the call in a service.

I found a solution with mutiny

@GET
@Path("type")
@Produces(MediaType.APPLICATION_JSON)
public Uni<Response> get() {
      return Uni.createFrom().item(alertTypeService.findAll().get())
            .onItem().transform(data -> Response.ok(data))
            .onFailure().recoverWithItem(err -> Response.status(600, err.getMessage()))
            .onItem().transform(ResponseBuilder::build)
            .emitOn(Infrastructure.getDefaultExecutor())
}

Where alertTypeService.findAll() return a supplier

@Transactional(Transactional.TxType.NEVER)
public Supplier<Set<AlerteTypeDTO>> findAll() {
   return () -> alerteTypeDAO.streamAll()
      .map(AlertTypeDTOMapper::mapToDTO)
      .collect(Collectors.toSet());
}

I don't know if this is the right solution but it works. This way the service provides a supplier which will be invoked by the correct thread. At least that's how I understood it.

Related