I am trying to call one method 12 times asynchronously. But before the call I am setting something different for each method call. How can I do this in a more elegant way.
I am using spring as well.
I am aware of #async but how can I change the body 12 times ?
Callable<Object> task4 = () -> {
CallContextHolder.setContext(callContext);
try {
Object m = dbQuery(userId);
if (m == null){
throw new RuntimeException();
}
return m;
}
catch (Exception e) {
throw new IllegalStateException("task interrupted", e);
}
};
Callable<Object> task5 = () -> {
CallContextHolder.setContext(callContext); //here is the difference in every task
try {
Object m = dbQuery(userId);
if (m == null){
throw new RuntimeException();
}
return m;
}
catch (Exception e) {
throw new IllegalStateException("task interrupted", e);
}
You can use something like the following method
public Callable<Object> getCallable(CallContext context, String userId) { //replace types fro parameters to appropriate
return () -> {
CallContextHolder.setContext(callContext);
try {
Object m = dbQuery(userId);
if (m == null){
throw new RuntimeException();
}
return m;
}
catch (Exception e) {
throw new IllegalStateException("task interrupted", e);
}
};
}
And use it like this
Callable<Object> call1 = getCallable(callContext, userId);
Callable<Object> call2 = getCallable(callContext, userId);
You can try to use some type of loop to generate those callables and store them in a list.
Related
I have lots of calls against a REST API that i want handled the same way.
Perform call, check if not authenticated. Refresh Token call again or if we hit rate
limit despite rate limit function. Sleep and perform call again.
I would like to wrap this in a function that can be called in the way
ReturnType returnVal= handleIntegration(ReturnType , functionToBecCalled)
How can this be achieved?
For the example below something like
CustomersResponse customersReponse = handleIntegration(CustomersResponse , connection.customers.findCustomersResponse())
EmployeesReponse employeesRepsonse = handleIntegration(EmployeeResponse , connection.employees.findEmployeesResponse())
//Current Code
bucket.consume();
CustomersResponse customersResponse = null;
try {
customersResponse = connection.customers.findCustomersResponse();
} catch (IntegrationException e) {
if (e.getStatusCode() == 401) {
this.newAccessFromRefreshToken();
customersResponse = connection.customers.findCustomersResponse();
}else if (e.getStatusCode() == 429){
Thread.sleep(500);
customersResponse = connection.customers.findCustomersResponse();
}else
throw e;
}
bucket.consume();
EmployeeResponse employeeResponse = null;
try {
employeeResponse = connection.employees.findEmployeesResponse();
} catch (IntegrationException e) {
if (e.getStatusCode() == 401) {
this.newAccessFromRefreshToken();
employeeResponse = connection.employees.findEmployeesResponse();
}else if (e.getStatusCode() == 429){
Thread.sleep(500);
employeeResponse = connection.employees.findEmployeesResponse();
}else
throw e;
}
You could try something like the following with the help of Java 8+ Functional Interfaces and Generics:
public <T> T handleIntegration(Supplier<T> supplier) {
bucket.consume();
T result = null;
try {
result = supplier.get();
} catch (IntegrationException e) {
if (e.getStatusCode() == 401) {
this.newAccessFromRefreshToken();
result = supplier.get();
} else if (e.getStatusCode() == 429) {
Thread.sleep(500);
result = supplier.get();
} else
throw e;
}
return result;
}
Then you could call the method like this:
CustomersResponse returnVal = handleIntegration(connection.customers::findCustomersResponse)
If you are at least on Java 8 with lambdas, you can do it like this:
<T> T handleIntegration(Supplier<T> method) {
bucket.consume(); // I don't know how this fits - BEWARE!
T response = null;
try {
response = method.get();
} catch (IntegrationException e) {
if (e.getStatusCode() == 401) {
this.newAccessFromRefreshToken();
response = method.get();
} else if (e.getStatusCode() == 429){
Thread.sleep(500);
response = method.get();
} else
throw e;
}
}
// I don't know what you want to do with the response, returning it here for example
return response;
}
And use it e.g. as:
CustomersResponse customersReponse = handleIntegration(
CustomersResponse.class,
() -> connection.customers.findCustomersResponse()
);
Caveat: I assumed IntegrationException is an unchecked exception. If it is checked or in any case, e.g. connection.customers.findCustomersResponse() throws a checked exception, the provided java.util.function.Supplier will not do. You will have to provide a functional interface that throws the specific checked exception.
Unrelated Note: Thread.sleep() is easy, but you may want to consider a better way, because sleep blocks the thread.
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();
}
}
I'm struggling with the functional style of Supplier<U>, etc and creating testable code.
So I have an InputStream that is split into chunks which are processed asynchronously, and I want to know when they are all done. To write testable code, I outsource the processing logic to its own Runnable:
public class StreamProcessor {
public CompletableFuture<Void> process(InputStream in) {
List<CompletableFuture> futures = new ArrayList<>();
while (true) {
try (SizeLimitInputStream chunkStream = new SizeLimitInputStream(in, 100)) {
byte[] data = IOUtils.toByteArray(chunkStream);
CompletableFuture<Void> f = CompletableFuture.runAsync(createTask(data));
futures.add(f);
} catch (EOFException ex) {
// end of stream reached
break;
} catch (IOException ex) {
return CompletableFuture.failedFuture(ex);
}
}
return CompletableFuture.allOf(futures.toArray(CompletableFuture<?>[]::new));
}
ChunkTask createTask(byte[] data) {
return new ChunkTask(data);
}
public class ChunkTask implements Runnable {
final byte[] data;
ChunkTask(byte[] data) {
this.data = data;
}
#Override
public void run() {
try {
// do something
} catch (Exception ex) {
// checked exceptions must be wrapped
throw new RuntimeException(ex);
}
}
}
}
This works well, but poses two problems:
The processing code cannot return anything; it's a Runnable after all.
Any checked exceptions caught inside ChunkTask.run() must be wrapped into a RuntimeException. Unwrapping the failed combined CompletableFuture returns the RuntimeException which needs to be unwrapped again to reach the original cause - in contrast to the IOException.
So I'm looking for a way to do this with CompletableFuture.supplyAsync(), but I can't figure out how to do this without lambdas (bad to test) or to return a CompletableFuture.failedFuture() from the processing logic.
I can think of two approaches:
1. With supplyAsync:
When using CompletableFuture.supplyAsync, you need a supplier instead of a runnable:
public static class ChunkTask implements Supplier<Object> {
final byte[] data;
ChunkTask(byte[] data) {
this.data = data;
}
#Override
public Object get() {
Object result = ...;
// Do something or throw an exception
return result;
}
}
and then:
CompletableFuture
.supplyAsync( new ChunkTask( data ) )
.whenComplete( (result, throwable) -> ... );
If an exception happens in Supplier.get(), it will b e propagated and you can see it in CompletableFuture.whenComplete, CompletableFuture.handle or CompletableFuture.exceptionally.
2. Passing a CompletableFuture to the thread
You can pass a CompletableFuture to ChunkTask:
public class ChunkTask implements Runnable {
final byte[] data;
private final CompletableFuture<Object> future;
ChunkTask(byte[] data, CompletableFuture<Object> future) {
this.data = data;
this.future = future;
}
#Override
public void run() {
try {
Object result = null;
// do something
future.complete( result );
} catch (Throwable ex) {
future.completeExceptionally( ex );
}
}
}
Then the logic becomes:
while (true) {
CompletableFuture<Object> f = new CompletableFuture<>();
try (SizeLimitInputStream chunkStream = new SizeLimitInputStream(in, 100)) {
byte[] data = IOUtils.toByteArray(chunkStream);
startThread(new ChunkTask(data, f));
futures.add(f);
} catch (EOFException ex) {
// end of stream reached
break;
} catch (IOException ex) {
f.completeExceptionally( ex );
return f;
}
}
Probably, Number 2 is the one that gives you more flexibility on how to manage the exception.
CompletableFuture.supplyAsync(
() -> {
transporter.write(req);
//here take the value from a blocking queue,will throw a interruptedException
return responseQueue.take();
}, executorService);
The common method to deal with interruptedException is either to interrupt again or direct throw interruptedException, but both cannot work. Anyone have the idea?
I change the code like this.
CompletableFuture<Rep> result = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
transporter.write(req);
try {
Rep rep = responseQueue.take();
result.complete(rep);
} catch (InterruptedException e) {
result.completeExceptionally(e);
Thread.currentThread().interrupt();
} catch (Exception e) {
result.completeExceptionally(e);
}
}, executorService);
return result;
I ran into the same question, but after reading more from comments here and reference book I think you can do either one of these two:
1 (what I end up doing):
CompletableFuture.runAsync(() -> {
transporter.write(req);
try {
Rep rep = responseQueue.take();
result.complete(rep);
} catch (Exception e) {
throw new CompletionException(e);
}
}, executorService);
return result;
or 2:
CompletableFuture<Rep> result = new CompletableFuture<>();
new Thread(()-> {
transporter.write(req);
try {
Rep rep = responseQueue.take();
result.complete(rep);
} catch (Exception e) {
result.completeExceptionally(e);
}
}).start();
I know the 2nd one does not use the executorService, but I feel the whole point of using CompletableFuture is utilizing the CompletionStage APIs in functional-style.
#antak mentioned it buried in a comment, but I think the correct answer here is:
For CompletableFuture.supplyAsync() wrap it in java.util.concurrent.CompletionException and rethrow it.
So the sample code would look something like:
CompletableFuture.supplyAsync(
() -> {
transporter.write(req);
try {
//here take the value from a blocking queue,will throw a interruptedException
return responseQueue.take();
}
catch (InterruptedException e) {
throw new CompletionException(e);
}
}, executorService);
As lambda functions don't support throwing exceptions, I think Java developers will need a new paradigm. One thing that comes to mind is as follows:
public class ResultWrapper<R, E extends Exception> {
E exception;
R result;
}
Lambda functions can return instances of this wrapper. (Edit: your case)
CompletableFuture<ResultWrapper<String, InterruptedException>> aFuture = ...;
...
aFuture.supplyAsync(
() -> {
try {
transporter.write(req);
} catch(InterruptedException e) {
ResultWrapper<String, InterruptedException> r = new ResultWrapper<>();
r.exception = e;
r.result = null;
return r;
}
...
}, executorService);
I am having the code this way..
1) Invoking the updatedb method using reflection...
for (String uniqueSym : activeSymbolsSet) {
futureTaskUtil.submiteTask(new Helper(),
Helper.class.getDeclaredMethod("updateDb",
new Class<?>[] { String.class }), new Object[] { uniqueSym }, 60);
}
- futureTaskUtil:
2) My question is this updatedb is executed as an run time task...
public Object submiteTask(final Object obj, final Method method, final Object[] params, int timeoutSeconds) throws Exception {
if (null != obj && method != null) {
Callable<Object> task = new Callable<Object>() {
public Object call() {
try {
method.setAccessible(true);
Object resultObj = method.invoke(obj, params);
return resultObj;
} catch (Exception e) {
logger.fatal("Exception occured while invoking future task.", e);
}
return null;
}
};
Future<Object> future = executor.submit(task);
try {
Object result = null;
if (timeoutSeconds < 0) {
result = future.get(timoutsec, TimeUnit.SECONDS);
} else {
result = future.get(timeoutSeconds, TimeUnit.SECONDS);
}
logger.info("Result of method execution is :: " + result);
return result;
} catch (TimeoutException e) {
} catch (Exception e) {
logger.fatal("Exception occured while executing future tas : " + obj, e);
} finally {
future.cancel(true); // may or may not desire this
}
}
return null;
}
can some one explain why this is executed as an seperate task and invoking the method?
Future<Object> future = executor.submit(task); This is your culprit You can read about Executer Framework here
What if the method never returns? Then the application would hang at this point.
Using this wrapper, the method will be canceled after 60 seconds.