'blocking EntityManager operations
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
Solution 1:[1]
If you want to keep using non-reactive code, you can use @Blocking
annotation on the method get()
. It will offload the computation on a worker thread (instead of one IO thread).
Quarkus is really picky with IO thread, you cannot block them. And if you have something like a database call (or any remote call), that is blocking. So you cannot do it in an IO thread.
More info:
Solution 2:[2]
"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();
}
}
Solution 3:[3]
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Thanh Nhan |
Solution 3 | Sekaijin |