How to use executorService to make http call in J2EE application - java

I want to get an idea of using ManagedExecutorService in stateless bean. Basically i am trying to send a http call in a separate thread inside my j2EE application. executorService send this request and wait for x number of seconds to receive response, if no response comes in specified seconds OR get exeception then do another try(X times) and then finally give a feedback that either https service call successfully done or failed. Here is my code
#SuppressWarnings("EjbEnvironmentInspection")
#Resource
ManagedExecutorService executorService;
public static final long RETRY_DELAY = 3000;
public static final int MAX_RETRIES = 3;
executorService.execute(() -> {
int retry = 0;
Collection<Info> responseInfo = null;
while (responseInfo == null && retry++ < MAX_RETRIES) {
try {
responseInfo = httpsService.requestAccessInfo(requestInfo);
Thread.sleep(RETRY_DELAY);
} catch (Exception e) {
log.error("Error while receiving response retry attempt {}", retry);
}
}
boolean status = filledLockAccessInfo==null ? false : true;
event.fire(regularMessage(status,GENERATION_RESULT);
});
Can someone tell me is it a right way to do this OR not.

You shouldn't need to forcibly sleep (Thread.sleep(RETRY_DELAY);). What you need is an asynchronous invocation of the service that can support timeout.
The following two methods use the completable future API's timeout and error handling to implement that.
The following use recursion to retry the given number of times:
private static Collection<Info> callService(int retryCount) {
try {
CompletableFuture<Collection<Info>> f = invoke();
return f.get(RETRY_DELAY, TimeUnit.MILLISECONDS);
}catch(TimeoutException te) {
if(retryCount > 0) {
return callService(retryCount - 1);
} else {
throw new RuntimeException("Fatally failed!!");
}
} catch(Exception ee) {
throw new RuntimeException("Unexpectedly failed", ee);
}
}
Note that the executorService object is passed in the second argument of supplyAsync
private static CompletableFuture<Collection<Info>> invoke() {
return CompletableFuture.supplyAsync(() -> {
//call
return httpsService.requestAccessInfo(requestInfo);;
}, executorService);
}
With that, you can simply call it with the number of retries:
Collection<Info> responseInfo = callService(MAX_RETRIES);
To make the above call run asynchronously, you can replace the preceding statement with:
CompletableFuture.supplyAsync(() -> callService(MAX_RETRIES))
.thenAccept(res -> System.out.println("Result: " + res));
This will make the call in the background. Later, you can check how it completed:
f.isCompletedExceptionally() //will tell whether it completed with an exception.

Related

Timelimiter is not interrupting the thread

I am using resilience4j Timelimiter in my project.
The timelimiter is throwing an error if a request is taking more than 10s, but it is not interrupting the thread.
When call comes from postman, i have put the debug and tested, after 10s in postman it displays an exception, but the thread still executes the method and after that added some print statements and it executed as well.
How to cancel or interrupt the thread after 10s in resilience4j.
class A {
TimeLimiterConfig config = TimeLimiterConfig.custom().cancelRunningFuture(true)
.timeoutDuration(Duration.ofMillis(TimeLimit)).build();
TimeLimiterRegistry timeLimiterRegistry = TimeLimiterRegistry.of(config);
TimeLimiter timeLimiter = timeLimiterRegistry.timeLimiter("APITimelimiter", config);
public Response someMethod() throws Exception {
try {
timeLimiter.executeFutureSupplier(() -> CompletableFuture.supplyAsync(() -> {
return getData();
}));
} catch (Exception e) {
logger.error("Request has crossed the execution time of " + TimeLimit
+ " seconds");
throw new Exception("Your request has crossed the execution time of "+ TimeLimit+" seconds.");
}
}
public UserData getData() {
String jsonData = "";
return jsonData;
}
}
TimeLimiter cannot cancel a CompletableFuture. See #TimeLimiter times out slow method but does not cancel running future #905 Points out, that: the limited cancel() in case of CompletableFuture is not a bug, but a design decision. CompletableFuture is not inherently bound to any thread, while Future almost always represents background task.

Looking for ways to detect AWS Lambda timeouts(few seconds before timeout) in Java and to test the same

My current Lambda function is calling a 3rd party web service Synchronously.This function occasionally times out (current timeout set to 25s and cannot be increased further)
My code is something like:
handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
try{
response = calling 3rd party REST service
}catch(Exception e){
//handle exceptions
}
}
1)I want to custom handle the timeout (tracking the time and handling few milli seconds before actual timeout) within my Lambda function by sending a custom error message back to the client.
How can I effectively use the
context.getRemainingTimeInMillis()
method to track the time remaining while my synchronous call is running? Planning to call the context.getRemainingTimeInMillis() asynchronously.Is that the right approach?
2)What is a good way to test the timeout custom functionality ?
I solved my problem by increasing the Lambda timeout and invoking my process in a new thread and timing out the Thread after n seconds.
ExecutorService service = Executors.newSingleThreadExecutor();
try {
Runnable r = () ->{
try {
myFunction();
} catch (Exception e) {
e.printStackTrace();
}
};
f = service.submit(r);
f.get(n, TimeUnit.MILLISECONDS);// attempt the task for n milliseconds
}catch(TimeoutException toe){
//custom logic
}
Another option is to use the
readTimeOut
property of the RestClient(in my case Jersey) to set the timeout.But I see that this property is not working consistently within the Lambda code.Not sure if it's and issue with the Jersey client or the Lambda.
You can try with cancellation token to return custom exceptions with lambda before timeout.
try
{
var tokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(1)); // set timeout value
var taskResult = ApiCall(); // call web service method
while (!taskResult.IsCompleted)
{
if (tokenSource.IsCancellationRequested)
{
throw new OperationCanceledException("time out for lambda"); // throw custom exceptions eg : OperationCanceledException
}
}
return taskResult.Result;
}
catch (OperationCanceledException ex)
{
// handle exception
}

How to ignore a failed CompletableFuture call when multiple Async calls are made in Java?

I want to consume three REST service parallel calls in Java and my code is as below:
private CompletableFuture < EmployeesListResponse > makeAsyncCall(Request request) {
return CompletableFuture.supplyAsync(
() -> {
try {
LOGGER.warn("- - - - - Employees Service async call - - - - -");
return serviceObj.findServiceImpl(request);
} catch (Exception e) {
LOGGER.warn("service async call failed...", e);
}
return null;
}, asyncExecutor).handle((res, ex) -> {
LOGGER.warn("Exceptionally...", ex.toString(), res.toString());
return new EmployeesListResponse();
});
}
CompletableFuture < EmployeesListResponse > asyncFirstCall = makeAsyncCall(request);
CompletableFuture < EmployeesListResponse > asyncSecondCall = makeAsyncCall(request);
CompletableFuture < EmployeesListResponse > asyncThirdCall = makeAsyncCall(request);
CompletableFuture.allOf(asyncFirstCall, asyncSecondCall, asyncThirdCall).join();
In the above code, I am making three calls and joining them using CompletableFuture.allOf().join(). This code is working perfectly fine when the service response is 200 OK for all the three calls.
If one call fails(500 Internal Server Error or 404 Not Found) and other two service calls are 200 OK, then the code is throwing exception and the entire API response is getting failed with an exception. In this case, i want to ignore one service call with exception and return success response from the other two calls.
How to handle to ignore an exception in this scenario ?
So you're trying to wait for all 3 futures to complete before finishing, but the allOf future returns immediately when a single one fails. Instead you can explicitly wait on each:
List<CompletableFuture<String>> allFutures = Arrays.asList(asyncFirstCall, asyncSecondCall,
asyncThirdCall);
// await completion of all futures
allFutures.forEach(future -> {
try {
future.join();
} catch (CompletionException ex) {
// handled below.
}
});
if (allFutures.stream().filter(CompletableFuture::isCompletedExceptionally).count() > 2) {
throw new RuntimeException("Multiple failures");
}
// else continue with your business logic...
You don't need to handle the exception in try catch block as you are already handling handle() method. No matter you get the exception or not but this handle() method will execute every time. you just need to check if is there any exception if yes send default response as you want.
private CompletableFuture < EmployeesListResponse > makeAsyncCall(Request request) {
return CompletableFuture.supplyAsync(
() -> {
LOGGER.warn("- - - - - Employees Service async call - - - - -");
return serviceObj.findServiceImpl(request);
}, asyncExecutor).handle((res, ex) -> {
if (ex != null) {
LOGGER.warn("Exceptionally...", ex);
return "what ever default you want to return";
// or return new EmployeesListResponse();
}
return res;
});
}
If you want to ignore, try like below
CompletableFuture<Void> allOf = CompletableFuture.allOf(asyncFirstCall,asyncSecondCall);
allOf.whenComplete((aVoid, throwable) -> {
allOf.join();
});

Is it possible to check time being taken by a method call in parallel

In a Spring Boot service class, let's say that I am making a method call processEvent().
The method processEvent() might be doing N number of things including making REST calls to other services.
How to check the time being taken by the method in parallel and if it crosses the threshold, then do something else e.g. throw exception ?
class EventService {
public void processEvent(ServiceContext context, Event event) {
// Field a time checker here for the below method.
processEvent(event);
}
public void processEvent(Event event) {
// this method does many things.
}
}
Can this be achieved using CompletionService ? If yes, Please give an example!
EDIT:
The following code works but I have one query:
public void processEvent(ServiceContext context, Event event) {
LOGGER.debug("Timestamp before submitting task = {}", System.currentTimeMillis());
Future<EventResponse> future = executor.submit(() -> {
LOGGER.debug("Timestamp before invoking = {}", System.currentTimeMillis());
EventResponse eventResponse = processEvent(event);
LOGGER.debug("Timestamp after invoking = {}", System.currentTimeMillis());
return eventResponse;
});
try {
LOGGER.debug("Thread sleep starts at = {}", System.currentTimeMillis());
Thread.sleep(5000);
LOGGER.debug("Thread sleep ended at = {}", System.currentTimeMillis());
} catch (InterruptedException e) {
LOGGER.debug("Going to print stack trace....");
e.printStackTrace();
}
if (!future.isDone()) {
future.cancel(true);
LOGGER.debug("task executor cancelled at = {}", System.currentTimeMillis());
} else {
EventResponse response = future.get();
LOGGER.debug("Received Event ID = {}", response.getEventDetailsList().get(0).getEventID());
return response;
}
LOGGER.debug("Going to return error response at = {}", System.currentTimeMillis());
throw new Exception("Message");
}
I am getting the below logs:
Timestamp before submitting task = 1579005638324
Thread sleep starts at = 1579005638326
Timestamp before invoking = 1579005638326
Thread sleep ended at = 1579005638526
task executor cancelled at = 1579005638527
Going to return error response at = 1579005638527
Timestamp after invoking = 1579005645228
How "Timestamp after invoking" is logged after "task executor cancelled at" ?
You can use ThreadPoolTaskExecutor to submit the task, then sleep for a certain amount of time, then check if the task is completed and interrupt it, if it's still working. However, you can't just kill the task, you'll have to periodically check for the interrupted flag inside the task itself. The code would be something like:
#Autowired
private ThreadPoolTaskExecutor executor;
// ...
Future<?> future = executor.submit(() -> {
doOneThing();
if(Thread.interrupted()) {
return;
}
doAnotherThing();
if(Thread.interrupted()) {
return;
}
// etc.
});
Thread.sleep(10000);
if (!future.isDone()) {
future.cancel(true);
}
You can use a mix of a standard ThreadPoolExecutor with a ScheduledThreadPoolExecutor. The latter will cancel the submission of the former if it's still running.
ThreadPoolExecutor executor = ...;
ScheduledThreadPoolExecutor watcher = ...;
Future<?> future = executor.submit(() -> { ... })
watcher.schedule(() -> future.cancel(true), THRESHOLD_SECONDS, TimeUnit.SECONDS);
The future.cancel(true) will be a no-op if it completed. For this though, you should be aware of how to handle cross-thread communiccation and cancellation. cancel(true) says "Either prevent this from running entirely, or, if it is running, interrupt the thread indicating we need to stop execution entirely and immediately"
From there your Runnable should handle interruption as a stop condition:
executor.submit(()-> {
// do something
if(Thread.currentThread().isInterrupted()) {
// clean up and exit early
}
// continue doing something
});

Java : ExecutorService : newFixedThreadPool

This may be bit old question. I am confused with the ExecutorService work in Jboss environment. I used some sample code, where i am submitting the task with ExecutorService and after everything is done i am shutdown the executor.
Problem i am facing is after submitting one request, i am getting below exception for subsequent request.
Caused by: java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask#518ad6a2 rejected from java.util.concurrent.ThreadPoolExecutor#72114f80[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 0]
ExecutorService executorService = Executors.newFixedThreadPool(3);
#POST
#Path("/request")
public Response checkAsync(final MultiMedia multiMedia) {
final Random rand = new Random();
final String random = String.valueOf(rand.nextInt(50) + 1);
multiMediaJobs.put(random, multiMedia);
final String jobId = "{ 'jobId' : " + random + "}";
executorService.submit(new Runnable() {
#Override
public void run() {
boolean result = veryExpensiveOperation(jobId);
if (result) {
try {
MultiMedia multiMedia = (MultiMedia) multiMediaJobs.get(random);
multiMedia.getMediadata().getMetadata()
.setAssetId(random);
final String uri = multiMedia.getCallback().getUri()+multiMedia.getCallback().getResource();
RestTemplate restTemplate = new RestTemplate();
String code = restTemplate.postForObject(uri,
multiMedia, String.class);
System.out.println(code);
} finally {
logger.debug("Map size: " + multiMediaJobs.size());
logger.debug("Time: "+System.currentTimeMillis());
multiMediaJobs.remove(random);
}
}
}
private boolean veryExpensiveOperation(String jobId) {
try {
Thread.sleep(7000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.debug("Task is processed fully");
return true;
}
});
executorService.shutdown();
try {
executorService.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Response.status(Status.ACCEPTED)
.entity(commonHelper.toJSON(jobId)).build();
}
Is it really required to call shutdown in JBOSS environment? If i remove that it is accept all my request. Example i am seeing in all here is just main method. I just want to know how it works in real application.
Forgive me if i am misunderstood some concept.
The problem is that you shutdown the ExecutorService. So any subsequent task being submitted is rejected right away.
I think you have some misunderstanding here.
When you submit to an executor, you will normally get a Future<T> object back. If you need a result from this, you'll call Future.get() and that will block until the threadpool executes your job. Otherwise you can just leave your jobs to be executed.
You wouldn't normally shutdown the executor unless you really want to shut it down, not accept any jobs, and let those queued up execute.

Categories