How can I release the semaphore when two futures are completed? - java

I am having a Springboot java application that talks to cassandra database and also using google guava libaries.
currently i am facing a an issue. I have a semaphore object in the code.
in my my method i have to perform two write queries simulatenously using two objects( mapper and parameterisedListMsisdnMapper).
Firing each queries using the mappers returns ListenableFuture future & ListenableFuture future1 objects . How can I rewrited the below code, so that i will release the semaphore upon completion of both future and future1 object.
public class ParameterisedListItemRepository {
public ParameterisedListItemRepository() {
this.executor = MoreExecutors.directExecutor();
this.semaphore = new Semaphore(getNumberOfRequests(session));
}
public void saveAsync(ParameterisedListItem parameterisedListItem) {
try {
semaphore.acquire();
ListenableFuture<Void> future = mapper.saveAsync(parameterisedListItem);
ListenableFuture<Void> future1 = parameterisedListMsisdnMapper.saveAsync( mapParameterisedList(parameterisedListItem));
future.addListener(() -> semaphore.release(), executor);
} catch (InterruptedException e) {
throw new RuntimeException("Semaphore was interrupted.");
}
}
}
appreciate any help

I have used Futures.whenAllSucceed and it worked
public void saveAsync(ParameterisedListItem parameterisedListItem) {
if (parameterisedListItem.getId() == null) {
parameterisedListItem.setId(UUID.randomUUID());
}
Set<ConstraintViolation<ParameterisedListItem>> violations = validator.validate(parameterisedListItem);
if (violations != null && !violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
Callable releasePermit = () -> { semaphore.release();
return null;
};
try {
semaphore.acquire();
ListenableFuture<Void> future1 = mapper.saveAsync(parameterisedListItem);
ListenableFuture<Void> future2 = parameterisedListMsisdnMapper.saveAsync( mapParameterisedList(parameterisedListItem));
Futures.whenAllSucceed(future1, future2).call(releasePermit, executor);
} catch (InterruptedException e) {
//FIXME handle exception in better way
throw new RuntimeException("Semaphore was interrupted.");
}
}

Related

Resubmit Callable to executorService on exception

My situation
I'm trying to craft a functionality which would execute n (where n >=0) requests to a given endpoint, but I do understand that sometimes that endpoint might not respond due to
500 error or other issue, so I want to repeat my requests to an endpoint (with a
small interval in between [not yet implemented]) till I get a response, or till I get an unknown error which would indicate what I can't repeat, because of other reasons than a crashed server.
So, I've tried to implement this piece of functionality using Executors and concurrency provided by Java 11 and it does not work as I want
I can't resubmit failed tasks till I get all the responses and I don't know why
I have a method
private void DoMyTasks(List<MyRequest> requests) {
final ExecutorService executorService = Executors.newFixedThreadPool(10);
final ExecutorCompletionService<MyReqResDto> completionService =
new ExecutorCompletionService<>(executorService);
for (final MyRequest MyRequest : requests) {
completionService.submit(new MyCallableRequest(webClient, MyRequest));
}
List<MyReqResDto> responses = new ArrayList<>();
for (int i = 0; i < requests.size(); ++i) {
try {
final Future<MyReqResDto> future = completionService.take();
if (future.get().getEx() != null) {
completionService.submit(new MyCallableRequest(webClient, future.get().getMyRequest()));
}
responses.add(future.get());
} catch (ExecutionException | InterruptedException e) {
log.warn("Error"));
} catch (Exception exception) {
log.error("Other error");
} finally {
executorService.shutdown();
try {
if (!executorService.awaitTermination(10, TimeUnit.MINUTES)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
}
}
responses.size();
}
I'm trying to repeat failed tasks with
if (future.get().getEx() != null) {
completionService.submit(new MyCallableRequest(webClient, future.get().getMyRequest()));
}
and yet, at the end of execution I don't get all responses for my requests. What I get is at most 3 to 5 responses when I try executing 10 requests. Why? How to fix it?
My callable class is
public class MyCallableRequest implements Callable<MyReqResDto> {
private final WebClient webClient;
private final MyRequest myRequest;
public MyCallableRequest(WebClient webClient, MyRequest myRequest) {
this.webClient = webClient;
this.myRequest = myRequest;
}
#Override
public MyReqResDto call() throws Exception {
try {
if (new Random().nextInt(10) % 2 == 0) {
throw new TestException();
}
if (new Random().nextInt(10) % 7 == 0) {
throw new RuntimeException();
}
WebClient.UriSpec<WebClient.RequestBodySpec> uriSpec = webClient.post();
WebClient.RequestBodySpec bodySpec = uriSpec.uri(
s -> s.path("/myEndpoint").build());
MyRequestDto myMyRequestDto = new MyRequestDto();
WebClient.RequestHeadersSpec<?> headersSpec =
bodySpec.body(Mono.just(myMyRequestDto), MyRequestDto.class);
ResponseDto responseDto = headersSpec.exchangeToMono(s -> {
if (s.statusCode().equals(HttpStatus.OK)) {
return s.bodyToMono(ResponseDto.class);
} else if (s.statusCode().is1xxInformational()) {
return s.createException().flatMap(Mono::error);
} else if (s.statusCode().is3xxRedirection()) {
return s.createException().flatMap(Mono::error);
} else if (s.statusCode().is4xxClientError()) {
return s.createException().flatMap(Mono::error);
} else if (s.statusCode().is5xxServerError()) {
return s.createException().flatMap(Mono::error);
} else {
return s.createException().flatMap(Mono::error);
}
//return null;
}).block();
return new MyReqResDto(myRequest, responseDto, null);
} catch (Exception exception) {
return new MyReqResDto(myRequest, null, exception);
}
}
}
Update NO. 1
I changed a for loop to a while loop according to a comment provided by
Slaw and an answer provided by erickson. And this solutions works, meaning that
it is hammering an endpoint till all responses are received without
any errors. But I'm still not sure it feels that I'm building a sh**
tower with this solution. Is there any thread related issues that I should be aware while using executor like this?
while (true) {
Future < MyReqResDto > future = null;
try {
future = completionService.take();
if (future.get().getEx() != null /*and check exception if possible to handle, if not break from a loop*/) {
completionService.submit(new MyCallableRequest(webClient, future.get().getRequestCT());
} else {
responseDtos.add(future.get());
}
} catch (ExecutionException | InterruptedException e) {
log.warn("Error while downloading", e.getCause());
// test if I can recover from these exceptions if no
break;
}
}
if (responseDtos.size() == requests.size()) {
executorService.shutdown();
try {
if (!executorService.awaitTermination(10, TimeUnit.MINUTES)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
break;
}
You are shutting down the executor as soon as you get one response. Perhaps a few more have completed in this time, but you are not allowing time for any others to complete.
Your logic here is wrong. The executor should only be shut down when you are sure no more tasks will be submitted; at soonest, that is after the loop responsible for re-submitting failures.
Here is a simplified view of your code to highlight the premature shutdown:
for (int i = 0; i < requests.size(); ++i) {
try {
final Future<MyReqResDto> future = completionService.take();
...
responses.add(future.get());
...
} finally {
executorService.shutdown();
}
}

Java 8 completable future to execute methods parallel

I have 3 methods that I need to run in parallel, since they are independent to each other and combine the results of each one at the end and send it as the response. I need to handle exception as well.
In different post I found the below code and modified accordingly.
public Response getResponse() {
Response resultClass = new Response();
try {
CompletableFuture<Optional<ClassA>> classAFuture
= CompletableFuture.supplyAsync(() -> service.getClassA() );
CompletableFuture<ClassB> classBFuture
= CompletableFuture.supplyAsync(() -> {
try {
return service.getClassB();
}
catch (Exception e) {
throw new CompletionException(e);
}
});
CompletableFuture<ClassC> classCFuture
= CompletableFuture.supplyAsync(() -> {
try {
return service.getClassC();
} catch (Exception e) {
throw new CompletionException(e);
}
});
CompletableFuture<Response> responseFuture =
CompletableFuture.allOf(classAFuture, classBFuture, classCFuture)
.thenApplyAsync(dummy -> {
if (classAFuture.join().isPresent() {
ClassA classA = classAFuture.join();
classA.setClassB(classBFuture.join());
classA.setClassC(classCFuture.join());
response.setClassA(classA)
}
return response;
});
responseFuture.join();
} catch (CompletionExecution e) {
throw e;
}
return response;
}
Should the above run correctly in parallel? I see it takes some more time, and I wanted to make sure I am doing it right.
If you want to run methods in parallel you should use ExecutorService. Try something like that:
ExecutorService myExecutor = Executors.newFixedThreadPool(3);
List<Future<Object>> futures = myExecutor.invokeAll(
Arrays.asList(
() -> service.getClassA(),
() -> service.getClassB(),
() -> service.getClassC(),
)
);
myExecutor.shutdown();
The idea is correct, but this all could be done with a lot less code:
public Response getResponse() {
CompletableFuture<Optional<ClassA>> classAFuture = CompletableFuture.supplyAsync(() -> service.getClassA());
CompletableFuture<ClassB> classBFuture = CompletableFuture.supplyAsync(() -> service.getClassB());
CompletableFuture<ClassC> classCFuture = CompletableFuture.supplyAsync(() -> service.getClassC());
try {
return CompletableFuture.allOf(classAFuture, classBFuture, classCFuture)
.thenApply(() -> {
Response response = new Response();
Optional<ClassA> maybeA = classAFuture.get();
if (maybeA.isPresent()) {
ClassA classA = maybeA.get();
classA.setClassB(classBFuture.get());
classA.setClassC(classCFuture.get());
response.setClassA(classA);
}
return response;
}).get();
} catch (ExecutionException e) { // Ususally the exception is wrapped to ExecutionException by java concurrency framework itself
Throwable cause = e.getCause();
if (cause != null) {
throw cause;
} else {
throw e;
}
}
}
Main things:
You don't need to wrap your exceptions to CompletionException.
You don't need to use thenApplyAsync. Just thenApply is the same thing unless you want to be very specific on the type of thread you want to use. Check this for more information https://stackoverflow.com/a/47489654/3020903
You don't need to join() anything. By the time CompletableFuture.all has finished, you can be very sure that all the supplied jobs have finished and calling get() on then will just return the value.
As for can you be sure jobs A, B and C will be run in parallel. Yes and no. It will be run in parallel if there are enough system resources to run them in parallel. You have done your best to ask them to run in parallel. Maybe at some point you also want to supply your custom thread pool to have more control, but that's a topic for another day.

Java Using CountDownLatch to poll a method until a success response

I am trying to call a method multiple times every 60 seconds until a success response from the method which actually calls a rest end point on a different service. As of now I am using do while loop and using
Thread.sleep(60000);
to make the main thread wait 60 seconds which I feel is not the ideal way due to concurrency issues.
I came across the CountDownLatch method using
CountDownLatch latch = new CountDownLatch(1);
boolean processingCompleteWithin60Second = latch.await(60, TimeUnit.SECONDS);
#Override
public void run(){
String processStat = null;
try {
status = getStat(processStatId);
if("SUCCEEDED".equals(processStat))
{
latch.countDown();
}
} catch (Exception e) {
e.printStackTrace();
}
}
I have the run method in a different class which implements runnable. Not able to get this working. Any idea what is wrong?
You could use a CompletableFuture instead of CountDownLatch to return the result:
CompletableFuture<String> future = new CompletableFuture<>();
invokeYourLogicInAnotherThread(future);
String result = future.get(); // this blocks
And in another thread (possibly in a loop):
#Override
public void run() {
String processStat = null;
try {
status = getStat(processStatId);
if("SUCCEEDED".equals(processStat))
{
future.complete(processStat);
}
} catch (Exception e) {
future.completeExceptionally(e);
}
}
future.get() will block until something is submitted via complete() method and return the submitted value, or it will throw the exception supplied via completeExceptionally() wrapped in an ExecutionException.
There is also get() version with timeout limit:
String result = future.get(60, TimeUnit.SECONDS);
Finally got it to work using Executor Framework.
final int[] value = new int[1];
pollExecutor.scheduleWithFixedDelay(new Runnable() {
Map<String, String> statMap = null;
#Override
public void run() {
try {
statMap = coldService.doPoll(id);
} catch (Exception e) {
}
if (statMap != null) {
for (Map.Entry<String, String> entry : statMap
.entrySet()) {
if ("failed".equals(entry.getValue())) {
value[0] = 2;
pollExecutor.shutdown();
}
}
}
}
}, 0, 5, TimeUnit.MINUTES);
try {
pollExecutor.awaitTermination(40, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}

JUnit for future.get() Exception scenario

I need to test InterruptedException and ExecutionException and write JUnits for the same.
Please advice me on this. How can i interrupt the threads to replicate the scenario. The populateDataForm will start new threads and add this to futures list.
Here is my sample code:
class MyTest{
public populateData(){
Collection<Future<?>> futures = new LinkedList<Future<?>>();
DataSet ds = Helper.populateDataForm(employee, futures);
waitForTaskCompletion(futures);
}
private waitForTaskCompletion(futures){
for (Future<?> future:futures) {
try {
future.get();
} catch (InterruptedException e) {
throw new CustomExcpetion("Message1", e)
} catch (ExecutionException e) {
throw new CustomExcpetion("Message2", e)
}
}
}
You can inherit from MyTest and overload populateData() method as follows:
public void populateData() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<String> calls = new Callable<String>() {
#Override
public String call() throws Exception {
for (;;){
Thread.sleep(100);
// You call interrupt here, which causes Future.get() interrupt
Thread.currentThread().interrupt();
if (1 > 2) break;
}
return null;
}
};
final Future<String> future = executorService.submit(calls);
waitForTaskCompletion(future);
executorService.shutdown();
}
To test the ExecutionException throw RuntimeException instead of the interrupt as follows:
if (1==1)throw new RuntimeException();

Java - running jobs async using ReentrantLock?

The code below allows us to run a job while ensuring that only one job at a time can run by using ReentrantLock.
Is there any way to modify this code to run job.call() asynchronously and to return the MyConcurrentJobException to the client prior to starting the thread?
We tried wrapping the try/catch/finally block in a new Thread but the unlock and lock have to happen in the same thread so we get an IllegalMonitorException
??
final static Lock lock = new ReentrantLock();
public Object runJob(String desc, Callable job, boolean wait) {
logger.info("Acquiring lock");
if (!lock.tryLock()) {
throw new MyConcurrentJobException();
}
activeJob = new JobStatus(desc);
logger.info("Lock acquired");
try {
return job.call();
} catch (MarginServiceAssertionException e) {
throw e;
} catch (MarginServiceSystemException e) {
throw e;
} catch (Exception e) {
throw new MarginServiceSystemException(e);
} finally {
activeJob = null;
logger.info("Releasing lock");
lock.unlock();
logger.info("Lock released");
}
}
You can use Semaphore instead of ReentrantLock, its permits are not bound to thread.
Something like this (not sure what you want to do with the result of job.call() in the asynchronous case):
final static Semaphore lock = new Semaphore(1);
public void runJob(String desc, Callable job, boolean wait) {
logger.info("Acquiring lock");
if (!lock.tryAcquire()) {
throw new MyConcurrentJobException();
}
startThread(new Runnable() {
public void run() {
try {
job.call();
} finally {
lock.release();
}
}
});
}
I think I am misunderstanding completely because to block and wait while doing something asynchronously doesn't make too much sense to me unless some progress can be made on the invoking thread.
Could you do something like this:
final static Lock lock = new ReentrantLock();
final static ExecutorService service = Executors.newThreadPoolExecutor();
public Object runJob(String desc, Callable job, boolean wait) {
logger.info("Acquiring lock");
if (!lock.tryLock()) {
throw new MyConcurrentJobException();
}
activeJob = new JobStatus(desc);
logger.info("Lock acquired");
try {
Future<?> future = service.submit(job);
// This next line will block until the job is finished
// and also will hold onto the lock.
boolean finished = false;
Object o = null;
while(!finished) {
try {
o = future.get(300, TimeUnit.MILLISECONDS);
finished = true;
catch(TimeOutException e) {
// Do some periodic task while waiting
// foot.tapLots();
}
}
if (o instanceof MarginServiceAssertionException) {
throw ((MargineServiceAssertionException)o);
} else if (o instanceof MargineServiceSystemException) {
throw ((MarginServiceSystemException)o);
} else if (o instanceof Exception) {
throw new MarginServiceSystemException(e);
}
} catch (... InterruptedException e) { /// catch whatever exceptions throws as part of this
/// Whatever needs to be done.
} finally {
activeJob = null;
logger.info("Releasing lock");
lock.unlock();
logger.info("Lock released");
}
}

Categories