With reactive mailer I am trying to persist if the email was succeeded or not.
Here down the code snippet that is not woking:
#Path("atendimentos")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class AtendimentoResource {
#Inject
AtendimentoHistoricoRepository atendimentoHistoricoRepository;
#Inject
ReactiveMailer mailer;
#GET
public Response findAll(#QueryParam("nome") String nome) {
AtendimentoHistorico atendimentoHistorico = new AtendimentoHistorico();
mailer.send(email).subscribe().with(success -> {
atendimentoHistorico.setEmailEnviado(true);
atendimentoHistoricoRepository.persist(atendimentoHistorico);
}, error -> {
});
}
}
Here is the thrown exception:
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.
If you want to block, you should use io.quarkus.mailer.Mailer instead of ReactiveMailer.
#Path("atendimentos")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class AtendimentoResource {
#Inject
AtendimentoHistoricoRepository atendimentoHistoricoRepository;
#Inject
Mailer mailer;
#GET
public Response findAll(#QueryParam("nome") String nome) {
AtendimentoHistorico atendimentoHistorico = new AtendimentoHistorico();
mailer.send(email);
atendimentoHistorico.setEmailEnviado(true);
atendimentoHistoricoRepository.persist(atendimentoHistorico);
}
}
Related
I have implemented a REST endpoint in JavaEE that fires an asynchronous event to trigger a process each time the endpoint is used by a user.
This all works as intended and the process is triggered asynchronously, but results in a SEVERE level log: No valid EE environment for injection of TagsProcessor and I do not understand why.
Is this a bug in Payara? Or am I doing something wrong?
Here is an example implementation:
Rest endpoint where the event is fired on each login:
#Path("auth")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#RequestScoped
public class AuthenticationResource {
#POST
#Path("request-jwt")
#PermitAll
#Timed(name = "appV2RequestJwt", absolute = true)
public Response appRequestJwt(RefreshRequest refreshRequest) {
JwtResponse dto;
try {
dto = authenticationProcessor.appRequestJwt(refreshRequest);
//Fire asynchronous event
calculateTagsEvent.fireAsync(new CalculateTagsEvent(refreshRequest.getUsername()));
return Response.ok(dto).build();
} catch (Exception exception) {
LOGGER.log(Level.SEVERE, "Could not request jwt: {}", exception.getMessage());
dto = new JwtResponse(null, INTERNAL_SERVER_ERROR);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(dto).build();
}
}
}
Observer class:
#RequestScoped
public class TagsProcessor {
private static final Logger LOGGER = Logger.getLogger(TagsProcessor.class.getName());
#Inject
private BeanController beanController;
//Observe asynchronous event
public void manageCalculateTagsEvent(#ObservesAsync CalculateTagsEvent event) {
LOGGER.log(Level.WARNING, "Event observed");
beanController.create(new SomeBean());
}
}
This results in the logs:
[#|2022-08-17T06:39:39.461+0000|SEVERE|Payara 5.201||_ThreadID=473;_ThreadName=payara-executor-service-task;_TimeMillis=1660718379461;_LevelValue=1000;| No valid EE environment for injection of TagsProcessor|#]
[#|2022-08-17T06:39:39.473+0000|WARNING|Payara 5.201|TagsProcessor|_ThreadID=473;_ThreadName=payara-executor-service-task;_TimeMillis=1660718379473;_LevelValue=900;| Event observed|#]
So it's working as intended, but is giving me the warning about the injection...
As mentioned in my comment I did try various scopes but in the end it's supposed to be a #Stateless EJB that can be spawned from a pool without being attached to the client's state.
Hi I am new to multithreading in java. Can someone please help me with this:
My service:
#Async
public List<String> doSomething(int a){
//Do something
return list;
}
SpringbootApplication:
#SpringBootApplication
#EnableAsync
public class Test {
public static void main(String[] args) {
SpringApplication.run(Test.class, args);
}
}
Async config:
#Configuration
#EnableAsync
public class AsyncConfig {
#Bean(name ="taskExecutor")
public Executor taskExecutor(){
ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("userThread-");
executor.initialize();
return executor;
}
}
Controller:
#RestController
public class Controller{
#Autowired
private Service service;
#GetMapping("test")
public List<String> getAll(){
return service.doSomething(1);
}
}
When I hit this get request from postman it is showing up blank in the response. I understand that my call is going asynchronously and the response is coming back even before the my method is called. Is there any way to see this response by changing some settings in either my postman or spring boot application
If you want to process the request asynchronously but also want the API client to receive the response after it finishes processing such that from the client 's point of view , the request processing still looks like synchronous , the key is to use the Servlet3 asynchronous processing feature.
You do not need to configure it to execute asynchronously in the service level using #Aysnc. Instead configure the controller method to return CompletableFuture. Under the cover , it will trigger Servlet3 's asynchronous request processing which will process the request in another thread besides the HTTP thread that receive the request.
So your codes should look something like:
public class Service {
//No need to add #Async
public List<String> doSomething(int a){
return list;
}
}
#RestController
public class Controller{
#Autowired
private Service service;
#GetMapping("test")
public CompletableFuture<List<String>> getAll(){
return CompletableFuture.supplyAsync(()->service.doSomething(1));
}
}
For details about the Servlet3 asynchronous request processing supported in spring-mvc , you can refer to this blog series start from this .
You can return CompletableFuture. You will receive http response when CompleteableFuture will be completed.
Service:
#Async
public CompletableFuture<List<String>> doSomething() {
return CompletableFuture.completedFuture(Arrays.asList("1", "2", "3"));
}
Controller:
#GetMapping("test")
public CompletableFuture<List<String>> getAll(){
return service.getAll();
}
If you want to use async I would split your single request into so called "start task" and "get task result" requests. Your application returns "request id" for "start task" request. Then you use "request id" when performing "get task result". Such a scenario is a common way in the Batch Processing task. If you use Spring, you may be interesting investigating Spring Batch framework, which has Start/Stop/Restart job functionality among others.
I have a scenario in my springboot application, where I submit tasks into a threadpool for async execution.Now some of the methods inside child execution is part of aspect point advice with #AfterReturn.
I observe that even if processing is done asnyc, my main thread keeps executing the point cut advice from child thread and my service does not return a value until, all child thread finished execution.
Any pointer how to make the advice run on the executing thread itself?
So in short, controller method does not return response until dao method execution and its corresponding point cut is executed.
#Controller
#RequestMapping(value = "/api")
public class SampleController {
#Autowired
SampleService service;
#RequestMapping(value = "/action", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
#ResponseBody
public String action(#RequestBody String request){
service.action(request);
return "Success";
}
}
#Service
public class SampleService{
#Autowired
SampleDao dao;
#Async("threadPoolExecutor")
public void action(String request){
dao.action(request);
}
}
#Repository
public class SampleDao{
public void action(String request){
//do some db things
}
}
#Aspect
#Component
public class SampleAspect{
#AfterReturning(
pointcut = "execution( * com.sample.*.*.SampleDao.action(..))",
returning = "result")
public void audit(JoinPoint joinPoint, Object result) {
//dosome thing
}
}
The #Async on the service method does not mean that it will be submitted to the executor service and then return immediately, but that you can can have several incoming calls to the endpoint which will then be handled concurrently (this is the case per default anyway afaik, #Async is pretty much a marker only).
You can read this guide to see how this can be done properly.
The gist is that your service needs to create (and optionally return) some sort of Future (in the case of the post, CompletableFuture, as in
#Async
void serviceMethod(String request) {
CompletableFuture.submit(() -> dao.action(request));
}
It sounds like you do want to wait for the result to arrive though, so while this will work, I expect you'll run into problems later.
I have this JAX-RS resource
#Stateless
#Path("")
public class ServerResource {
#Inject
ServerService service;
#Resource
ManagedExecutorService mes;
#PUT
#Path("/prepare")
#Produces(MediaType.APPLICATION_JSON)
public void prepare(long id) {
var info = new Info();
info.setId(id);
service.saveInitialInfo(info);
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/submit")
public void submit(long id, #Suspended AsyncResponse response) {
mes.execute(() -> {
var info = service.getInfo(id);
if (info == null) {
response.resume(new Exception("not found"));
}
info.doLongComputation();
response.resume(info);
});
}
And this service
#Stateless
public class ServerService {
#PersistenceContext
EntityManager entityManager;
public void saveInitialInfo(Info info) {
entityManager.persist(info);
}
public Info getInfo(long id) {
return entityManager.find(Info.class, id);
}
}
Info is an #Entity with some fields (and an #Id long id) and doLongComputation() manipulates these fields and takes time.
The client calls prepare once. This creates an Info and persists it. Now the client will perform calls to submit multiple times (with the same id). The problem is that the changes to the entity done in doLongComputation() are not "saved". On the next submit call, the entity will be in the same state that it was persisted at at first.
Because doLongComputation takes a long time I am using an AsyncResponse and executing the method inside its new thread. The problem seems to be with doing the operations inside mes.execute. If I change the method to
public void submit(long id, #Suspended AsyncResponse response) {
var info = service.getInfo(id);
if (info == null) {
response.resume(new Exception("not found"));
}
info.doLongComputation();
response.resume(info);
}
then subsequent calls to submit will actually see the changes the previous calls did.
How can I #Inject into the asynchronous response method?
I am using JavaEE 8. Iv'e seen Java EE 7 - Injection into Runnable/Callable object but that one is for JavaEE 7 and also the solution of using #Inject Instance<ServerService> service and then calling service.get() inside the Runnable does not help, probably because my classes are managed and there he creates one with new.
I'm studying Jersey and I saw in a book you can use CompletableFuture (and CompletitionStage) in order to call your API in a NON-Blocking IO way.
But when I call the API with Postman, I always get 500.
If I debug the code I see that the methods are invoked correctly.
The first GET method is synchronous and works correcly.
The second and the third return error 500.
What am i missing?
#Path("/hello")
public class HelloController {
#GET
#Path("/first")
#Produces(MediaType.TEXT_PLAIN)
public String first() {
return "It works";
}
#GET
#Path("/second")
#Produces(MediaType.TEXT_PLAIN)
public CompletionStage<Response> second() {
return CompletableFuture.supplyAsync(() -> Response.accepted().entity("Hello!").build());
}
#GET
#Path("/third")
#Produces(MediaType.TEXT_PLAIN)
public CompletableFuture<Response> third() {
return CompletableFuture.supplyAsync(() -> Response.accepted().entity("Hello!").build());
}
}
This is the correct way to create an async endpoint with Jersey:
#POST
#Path("/goes")
#Consumes("application/json")
#Produces("application/json")
public void createTodoAsync3(#Suspended final AsyncResponse asyncResponse, Todo todo) {
CompletableFuture<Response> future = CompletableFuture.supplyAsync(() -> createTodo3(todo));
future.thenAccept(resp -> asyncResponse.resume(resp));
}
private Response createTodo3(Todo todo) {
//all logic goes here
return Response.accepted().entity(todo).build();
}