Im using Java 1.8, dropwizard 1.3.5, and swagger inflection 1.0.13 for my API.
I have a method which takes an HTTP Request, delays 20 seconds, then returns a 200 status code response:
public ResponseContext delayBy20Seconds(RequestContext context) {
ResponseContext response = new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
Thread.sleep(20000);
response.status(Response.Status.OK);
return response;
}
Say I want to return a 400 status code if the operation (which in this case takes 20 seconds), takes more than 15 seconds. How would I achieve this?
One way to do it without additional libraries is by using the java.util.concurrent package. The surest way to cancel a long-running task like this is by running it in a separate thread.
import java.util.concurrent.*;
...
private ExecutorService exec = Executors.newSingleThreadExecutor();
public ResponseContext delayBy20Seconds(RequestContext context) {
Callable<ResponseContext> task = new Callable<ResponseContext>() {
#Override
public ResponseContext call() throws Exception {
Thread.sleep(20000);
return new ResponseContext().contentType(MediaType.APPLICATION_JSON_TYPE);
}
};
List<Callable<ResponseContext>> tasks = new ArrayList<>();
tasks.add(task);
List<Future<ResponseContext>> done = exec.invokeAll(tasks, 15, TimeUnit.SECONDS);
Future<ResponseContext> task1 = done.get(0);
if (task1.isCancelled()) {
return some Error Response;
}
return task1.get();
}
Your ExecutorService should not be static, because you don't want to share it between threads for this particular use.
The Callable<ResponseContext> implementation is where the work for the long-running task is done. And as it should be obvious in the exec.invokeAll call we tell it how much we're willing to wait. The list of Futures returned will always contain as many elements as the list of tasks, so there's no need to check it for emptiness. We just have to check if the task completed or not.
You could use something like the TimeLimiter from the Google Guava library. This allows you to wrap a callable in an operation that you can call with Timeout. If the callable does not complete the operation in time, it will throw a TimeoutException which you can catch and return a 400 response.
As an example:
TimeLimiter timeLimiter = new SimpleTimeLimiter();
try {
String result = timeLimiter.callWithTimeout(
() -> doSomeHeavyWeightOperation(), 15, TimeUnit.SECONDS);
} catch (TimeoutException e) {
// return 400
}
Related
In the following code intention is to achieve asynchronous execution of a task provided it runs in less than 100 ms else timeout exception from other thread would be thrown ,
Question : What happens to the thread that is executing asynchronously for more than 100 ms , would it be released ? or it would wait for the task to complete without throwing exception ? ( wrote the code thinking that acceptEither would terminate the long running task once it encounters the timeOutException from the other future)
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public static <T> CompletableFuture<T> failAfter(long longValue) {
final CompletableFuture<T> timeoutFuture = new CompletableFuture<>();
scheduler.schedule(() -> {
final TimeoutException ex = new TimeoutException("Timing out");
return timeoutFuture.completeExceptionally(ex);
}, longValue, TimeUnit.MILLISECONDS);
return timeoutFuture;
}
final CompletableFuture<CustomResponse> CustomResponseFuture = CompletableFuture.supplyAsync(() -> object.taks()).
exceptionally(ex -> {
System.out.println("help");
return new "Hello";
});
CustomResponseFuture
.acceptEither(failAfter(100l), TesFutureStuff::myNewMethod)
.exceptionally(throwable -> {
System.out.println("failure "+throwable.getMessage());
return null;
})/*.getNow(null )*/;
If you just want a task that terminates after a specific amount of time, you don’t need CompletableFuture. Just create an ExecutorService, and call its invokeAny method.
If you insist on using CompletableFuture, you can use its get and cancel methods:
CompletableFuture<CustomResponse> future = CompletableFuture.supplyAsync(() -> object.task());
try {
CustomResponse response = future.get(100, TimeUnit.MILLISECONDS);
// process response here
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
System.out.println(e);
future.cancel(true);
}
Update:
To do the whole thing in the background, submit the invokeAny call to the same ExecutorService, but make sure the ExecutorService is not single threaded. There are many choices: Executors.newFixedThreadPool(2), Executors.newWorkStealingPool(), Executors.newCachedThreadPool, or even ForkJoinPool.commonPool().
For the CompletableFuture approach, I just noticed that as of Java 9, CompletableFuture adds an orTimeout method:
future.orTimeout(100, TimeUnit.MILLISECONDS);
I have a class which issues concurrent requests to two dependent services using CompletableFutures.
My code looks like this:
#Builder
#Slf4j
public class TestClass {
#NonNull private final ExecutorService threadPool = Executors.newFixedThreadPool(2);
#NonNull private final dependency1Client;
#NonNull private final dependency2Client;
public void myMethod() {
RequestObject1 firstDependencyRequest = RequestObject1.builder()
.attribute1("someValue")
.attribute2("secondValue");
CompletableFuture<ResultStructure1> future1 = CompletableFuture.supplyAsync(() -> dependency1Client.call(firstDependencyRequest), threadPool);
RequestObject2 secondDependencyRequest = RequestObject2.builder()
.attribute1("someValue")
.attribute2("secondValue");
CompletableFuture<ResultStructure2> future2 = CompletableFuture.supplyAsync(() -> dependency2Client.call(secondDependencyRequest), threadPool);
try {
CompletableFuture finalFuture = CompletableFuture.allOf(future1, future2);
} catch (ExecutionException|InterruptedException e) {
log.error("Exception calling dependency", e);
throw new RuntimeException(e);
}
}
}
I need the results from the two calls to the dependent services. How do I get them without performing a blocking call? I was initially thinking that I'd do future1 .get(), but that's a blocking call and I'll have to wait until I have the results from the first API call.
Is there a way to obtain the results from both the calls?
As the JavaDoc of CompletableFuture.allOf() indicates:
Otherwise, the results, if any, of the given CompletableFutures are not reflected in the returned CompletableFuture, but may be obtained by inspecting them individually.
What this means is indeed that you have to call join() or get() on them. It will not block if you do that in the chain after your allOf(), since it already guarantees that all of them are already completed.
Note that in your particular case, if you only have 2 futures, it is probably simpler to use thenCombine() which gives you access to the 2 results more easily.
I need to develop a web service operation with CXF 3 hosted by Tomcat 7. Our model layer is Spring 3.
This operation calls 16 other web services hosted by distant servers. We need to wait all responses in order to construct the response of our own operation.
We currently call each distant operations sequentially. Of course, we have response time issue. I think we should parallelize our operation inner calls and synchronize the different responses.
What kind of multithreading implementation can be safe? What can we do to make it better?
I'd use Java's generic Futures and a Spring's #Async methods in a #Service.
In short, you call the services sequentially and get all results as Futures, and then you simply check whether all the futures have finished proccessing. You can also do some work with partial data if there is such possibility.
Here's a simple example on how to do it. A sample service from the link:
#Service
public class GitHubLookupService {
RestTemplate restTemplate = new RestTemplate();
#Async
public Future<User> findUser(String user) throws InterruptedException {
System.out.println("Looking up " + user);
User results = restTemplate.getForObject("https://api.github.com/users/" + user, User.class);
// Artificial delay of 1s for demonstration purposes
Thread.sleep(1000L);
return new AsyncResult<User>(results);
}
}
And a method using it:
#Override
public void run(String... args) throws Exception {
// Start the clock
long start = System.currentTimeMillis();
// Kick of multiple, asynchronous lookups
Future<User> page1 = gitHubLookupService.findUser("PivotalSoftware");
Future<User> page2 = gitHubLookupService.findUser("CloudFoundry");
Future<User> page3 = gitHubLookupService.findUser("Spring-Projects");
// Wait until they are all done
while (!(page1.isDone() && page2.isDone() && page3.isDone())) {
Thread.sleep(10); //10-millisecond pause between each check
}
// Print results, including elapsed time
System.out.println("Elapsed time: " + (System.currentTimeMillis() - start));
System.out.println(page1.get());
System.out.println(page2.get());
System.out.println(page3.get());
}
I would use a traditional approach using join() to wait for the threads to finish instead of polling (I don't like polling pattern too much).
Kind of this for a generic thread to replicate:
public class ThreadedWebServiceRetrieval extends Thread {
private List<ResultObject> resultList;
private GenericWebServiceStub stub;
public ThreadedWebServiceRetrieval (List<ResultObject> resultList, GenericWebServiceStub stub) {
this.resultList = resultList;
this.stub = stub;
}
public void run() {
resultList.add(stub.retrieveData());
}
}
And this for the parallel retrieval code:
// ... Controller/Service stuff
List<ResultObject> resultList = new LinkedList<>();//Diamond operator
List<Thread> webServiceList = new LinkedList<>();
webServiceList.add(new ThreadedWebServiceRetrieval(resultList, stub1));
//...
webServiceList.add(new ThreadedWebServiceRetrieval(resultList, stubN));
for (Thread thread : webServiceList) {
thread.start();
}
for (Thread thread : webServiceList) {
thread.join();
}
// resultList is fulfilled
Time of this approach should be +/- longest retrieval.
I made the code VERY generic (overall in the Thread implementation) but it's intentional to fit most cases.
Enjoy!
I am using the Ebay API to place a bid on an item. If there is some kind of network error so that the API call does not return, I want to retry the call immediately afterwards. It seems so simple but I've been going round in circles all day. I'm not really experienced with threading. Is this how it's supposed to work or am I totally wrong?
Here is the Callable class:
public class PlaceOfferThread implements Callable<Boolean> {
private PlaceOfferCall call;
public Boolean isComplete;
public PlaceOfferThread (PlaceOfferCall p) {
call = p;
}
#Override
public Boolean call() throws Exception {
try {
call.placeOffer();
return true;
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
return false;
}
}
And here is the caller
int timeout = 10;
int maxRetries = 5;
int retries = 0;
ExecutorService executor = Executors.newSingleThreadExecutor();
PlaceOfferThread thread = new PlaceOfferThread(call);
boolean flag = false;
while (!flag && retries++ < maxRetries) {
Future<Boolean> future = null;
try {
future = executor.submit(thread);
flag = future.get(timeout, TimeUnit.SECONDS);
future.cancel(true);
}
catch(TimeoutException ex) {
// no response from Ebay, potential network issues
// resubmit the call to Ebay with the same invocation id
future.cancel(true);
}
catch (Exception threadException) {
// any other exception indicates that we got a response from Ebay
// it just wasn't the response we wanted
throw new Exception(threadException.getMessage());
}
}
executor.shutdown(); // TODO
If there is some kind of network error so that the API call does not return, I want to retry the call immediately afterwards.
I'm not 100% sure how your application is working right now but here are some thoughts:
When you call future.cancel(true) you most likely will not be stopping the current transaction. Unless you are using NIO calls, IO methods are not interruptible. Interrupting a thread just sets a flag on the thread and caused those few methods that throw InterruptedException (like sleep, wait, join) to do so. You'll have to watch the Thread.currentThread().isInterrupted() method to be able to see the interrupt otherwise.
I think the right thing to do is to set the connection and IO timeouts of the underlying http-client object and have it throw or exit with an error if there are problems. Trying to kill it from another thread is going to be much more difficult.
In looking at your code I'm not sure why you are using threads at all. Maybe you are doing other processing but it might be better to make the call directly. Then you can tune the HttpClient's IO timeouts and handle them appropriately.
I have a service which process a request from a user.
And this service call another external back-end system(web services). but I need to execute those back-end web services in parallel. How would you do that? What is the best approach?
thanks in advance
-----edit
Back-end system can run requests in parallel, we use containers like (tomcat for development) and websphere finally for production.
So I'm already in one thread(servlet) and need to spawn two tasks and possibly run them in parallel as close together as possible.
I can imagine using either quartz or thread with executors or let it be on Servlet engine. What is proper path to take in such a scenario?
You can use Threads to run the requests in parallel.
Depending on what you want to do, it may make sense to build on some existing technology like Servlets, that do the threading for you
The answer is to run the tasks in separate threads.
For something like this, I think you should be using a ThreadPoolExecutor with a bounded pool size rather than creating threads yourself.
The code would look something like this. (Please note that this is only a sketch. Check the javadocs for details, info on what the numbers mean, etc.)
// Create the executor ... this needs to be shared by the servlet threads.
Executor exec = new ThreadPoolExecutor(1, 10, 120, TimeUnit.SECONDS,
new ArrayBlockingQueue(100), ThreadPoolExecutor.CallerRunsPolicy);
// Prepare first task
final ArgType someArg = ...
FutureTask<ResultType> task = new FutureTask<ResultType>(
new Callable<ResultType>() {
public ResultType call() {
// Call remote service using information in 'someArg'
return someResult;
}
});
exec.execute(task);
// Repeat above for second task
...
exec.execute(task2);
// Wait for results
ResultType res = task.get(30, TimeUnit.SECONDS);
ResultType res2 = task2.get(30, TimeUnit.SECONDS);
The above does not attempt to handle exceptions, and you need to do something more sophisticated with the timeouts; e.g. keeping track of the overall request time and cancelling tasks if we run over time.
This is not a problem that Quartz is designed to solve. Quartz is a job scheduling system. You just have some tasks that you need to be executed ASAP ... possibility with the facility to cancel them.
Heiko is right that you can use Threads. Threads are complex beasts, and need to be treated with care. The best solution is to use a standard library, such as java.util.concurrent. This will be a more robust way of managing parallel operations. There are performance benefits which coming with this approach, such as thread pooling. If you can use such a solution, this would be the recommended way.
If you want to do it yourself, here is a very simple way of executing a number of threads in parallel, but probably not very robust. You'll need to cope better with timeouts and destruction of threads, etc.
public class Threads {
public class Task implements Runnable {
private Object result;
private String id;
public Task(String id) {
this.id = id;
}
public Object getResult() {
return result;
}
public void run() {
System.out.println("run id=" + id);
try {
// call web service
Thread.sleep(10000);
result = id + " more";
} catch (InterruptedException e) {
// TODO do something with the error
throw new RuntimeException("caught InterruptedException", e);
}
}
}
public void runInParallel(Runnable runnable1, Runnable runnable2) {
try {
Thread t1 = new Thread(runnable1);
Thread t2 = new Thread(runnable2);
t1.start();
t2.start();
t1.join(30000);
t2.join(30000);
} catch (InterruptedException e) {
// TODO do something nice with exception
throw new RuntimeException("caught InterruptedException", e);
}
}
public void foo() {
Task task1 = new Task("1");
Task task2 = new Task("2");
runInParallel(task1, task2);
System.out.println("task1 = " + task1.getResult());
System.out.println("task2 = " + task2.getResult());
}
}