Spring boot call async while others in progress - java

I have a requirement where I am validating a data hitting a rest call like
#Async
private void validate() throws WebClientResponseException {
this.webClient.method(HttpMethod.GET)
.uri(urlBuilder -> urlBuilder.path(uripath).build())
.retrieve()
.bodyToMono(Response.class).block();
// throws exception in case of validation failure
}
I am calling this function from another function
RETURN_TYPE func() {
validate();
//rest of the code and validations
service.save(input);
}
My requirement is validate() should be called asynchronously and rest of the code and validations should be called parallelly.
It should not execute service.save() until both of them finishes. Is it possible to do that?

Related

Call db from async method

I have a Controller that must accept a request and do not wait for the finishing of the processing, give a response.
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public void processEvent(#RequestBody RequestMyObjectDTO requestMyObjectDTO) {
MyProcessor.process(requestMyObjectDTO);
}
After I give a response, I must execute the processing.
#Async
public void process(RequestMyObjectDTO myRequestObject) {
List<TestObject> testObjects= repository.findAllTestObject();
if (testObjects.isEmpty()) {
return;
}
.............
Is there any difference in where I will go to the database, in the asynchronous method, or outside it? In my case in Controller for example.
How it will impact behavior and what approaches are better?
Given that I need a check:
List<TestObject> testObjects= repository.findAllTestObject();
if (testObjects.isEmpty()) {
return;
}
At the same time, I expect that the controller may receive millions of requests.

#EventListener annotated method with non-void return value doesn't trigger a new event

I've got a following method in which I am attemping to return a none void type and hoping to handle the published event by the same method (recursively).:
#EventListener
#Async
public GenericSpringEvent<?> onGenericEvent(GenericSpringEvent<?> event) throws InterruptedException {
Thread.sleep(5000);
System.out.println("Received spring generic event - " + event.getWhat() + ", thread id " + Thread.currentThread().getId());
return new GenericSpringEvent<String>(String.valueOf(System.currentTimeMillis()), true);
}
The method is innitially triggered by the following call within my application:
GenericSpringEvent<String> genericSpringEvent = new GenericSpringEvent<>("GENERIC - STRING - TRUE", true);
applicationEventPublisher.publishEvent(genericSpringEvent);
the listener is called only once. I would expect an endless loop instead. Can someone explain me how to achieve it. It doesn't have to be the same listener method though, I would like to understand how this non-void return feature works. Thanx!
You are publishing the GenericSpringEvent only once! that is the reason.
In order to publish it again, I see two options to do it:
1 - you have to do the same: applicationEventPublisher.publishEvent(genericSpringEvent); in your onGenericEvent method
2 - write some aspect around your onGenericEvent method so that after return you do applicationEventPublisher.publishEvent(returnedGenericSpringEvent);
Returning the event doesn't make it published, the method annotated with #EventListener is just like any other method so that's why it may have a non-void return.
it works in this way
#Async
#EventListener
public CompletableFuture<ResponseDTO> generateXml(RequestDTO requestDTO) {
Thread.sleep(5000);
logger.debug("First step completed");
return CompletableFuture.supplyAsync(() -> ResponseDTO.builder()
.build());
}
#Async
#EventListener
public void sendXml(ResponseDTO responseDTO) {
logger.debug("Second step completed");
}
Enjoy

How to implement wait in a method call in generic way

I am trying to implement a generic solution for third party API(work in async way) but not getting any idea that how i can implement a call for rest of my application in synchronized way. Basically API is working like take request, process it and then give response when it finish but in meanwhile open to receive other requests as well. So i put API response method in a thread so that monitor continuously either there is a response or not by calling api response method with time interval.
API have interface to take request like:
public void api_execute(string UUID,String request);
API response object:
public APIReponse
{
private String UUID;
private String response_string
// Getter setter
}
I want to write a wrapper on top of this API in which have a single method so that different objects of my application use this to send request and receive response. so UUID will be create by this wrapper class but i am not getting that how i will wait a caller object until i received some response and also distinguish which caller send which request. I was thinking by using observer pattern here but seems to be not fit with this scenario. Can someone give me a hint how i can implement this.
You create async task executor using thread pool
ExecutorService threadpool = Executors.newFixedThreadPool(3);
public Future<APIReponse> submitTask(APIRequest request) throws InterruptedException, ExecutionException {
System.out.println("Submitting Task ...");
Future<APIReponse> future = threadpool.submit(new Callable<APIReponse>() {
#Override
public APIReponse call() throws Exception {
api_execute(request,UUID);
return new APIReponse();
}
});
return future;

How to test async vertx eventbus handlers without sending reply

I have two microservices written with java vertx. They communicate via eventbus.
First one sends a message and second receives the message.
First idea: Only reply to Vertx eventbus messages in unit test.
I want to test that message is being processed without errors and therefore I write unit test on second microservice that checks the reply
eventbus.send("address", message, reply -> {
if (reply.succeeded()) {
context.async().complete();
} else {
context.fail();
}});
Now I have to send reply in my consumer, but I want to do it only in test, I do not need to send replies in production. I do not want to consume cpu and network to send replies in production. So what I am looking for is something like this:
vertx.eventBus().consumer("address", handler -> {
Boolean success = methodMayFail();
if ( MY_CONTEXT_IS_TEST || HANDLER_IS_LOCAL_AS_I_ONLY_SENT_LOCAL_MESSAGES_FROM_TEST) {
success ? handler.reply("ok") : handler.fail();
}
});
Second idea came after cdelmas comment and is in my own answer
To test async eventbus handler without reply you have to extract your business logic into service and split your test case into two. First for message passing, second for business logic.
ConsumerVerticle will look like this:
class ConsumerVerticle extends AbstractVerticle {
// this service is injected somehow, for example as constructor parameter
private MyService service;
...
public void start() {
vertx.eventBus().consumer("address", handler -> {
service.methodMayFail();
});
}
}
In async test implement mock of your service with overridden method methodMayFail() that will hold the async
class MockService extends MyService() {
private Async async;
public MockService(Async async) {
this.async = async;
}
#Override public void methodMayFail() {
async.complete()
}
}
And then inject the mock service into verticle
MockService service = new MockService(context.async());
ConsumerVerticle consumerVerticle = new ConsumerVerticle(service);
...
eventbus.send("address", message)
Somewhere in another class MyServiceTest test the implementation of methodMayFail().
It is a very bad practice to add code only for tests.
Although you don't reply, there is probably something you do in the consumer that can be checked, such as updating some state. This is what you should assert in your test, in my opinion.

How to retrieve result of an #Async method

I have a small Spring Boot app waiting for REST calls to start an async job. However what I'd like to do next is get results of those async jobs and store them in DB. But I don't know how to use object returned with Future asynchronically.
Here is more or less what I have:
#RequestMapping("/vlan/{id}/{name}")
public void performVLANConfig(#PathVariable("id") int id, #PathVariable("name") String name) {
logger.debug("Received req");
Future<ProcessedRequest> processedRequestFuture= asyncService.processVlan(id, name);
processedRequestRepository.save(processedRequest);
}
But now it just waits for async call to end. Is there any way to let the async method live its life and after it has completed store this completition error?
You need to attach a callback. If you using Future then you can't attach a callback to it, assign to a ListenableFuture instead, the service needs to return a ListenableFuture of course.
ListenableFuture<ProcessedRequest> future = asyncService.processVlan(id, name);
future.addCallback(new ListenableFutureCallback<ProcessedRequest>() {
#Override
public void onFailure(Throwable throwable) {
// deal with it
}
#Override
public void onSuccess(ProcessedRequest processedRequest) {
processedRequestRepository.save(processedRequest);
}
});

Categories

Resources