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!
Related
I've been developing Rest API's in Java. I want to convert them it into Async. The Two options I see is DeferredResult and CompletableFeature.
I don't seem to be find the difference between these two, and when to chose over another.
Any real time examples would be appreciated.
DeferredResult is spring class and it is just a container of the result (as its name implies) so we need to explicitly use some kind of thread pool (ForkJoinPool for example) to run our processing asynchronously. CompletableFuture is part of java.util.concurrent and allow to run the processing asynchronously. It implements Future and basically have the ability to compose, combine and execute asynchronous computation steps.
Simple example of both options:
#GetMapping(value = "/deferredResult")
public DeferredResult<Boolean> useDeferredResult() {
DeferredResult<Boolean> deferredResult = new DeferredResult<>();
deferredResult.onCompletion(() -> logResult((Boolean)deferredResult.getResult()));
ForkJoinPool.commonPool().submit(() -> {
deferredResult.setResult(processRequest());
});
return deferredResult;
}
#GetMapping(value = "/completableFuture")
public CompletableFuture<Boolean> useCompletableFuture() {
return CompletableFuture.supplyAsync(this::processRequest)
.thenApplyAsync(this::logResult);
}
private boolean logResult(Boolean result) {
System.out.println("Result: " + result);
return true;
}
private boolean processRequest() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
Notes:
By default, Spring will execute the CompletableFuture actions by
ForkJoinPool (can be configured).
In the case of DeferredResult, the logResult will be executed by the servlet container (for example Tomcat) worker thread - not nessecrally the one got the request at the beginning.
You can (while I don't see any
reason to) run processing asynchronously with CompletableFuture and
return DeferredResult.
With DeferredResult you can register more callbacks, like onCompleted - For example onError, etc. See here.
CompletableFuture has a lot options to compose actions. See here.
IMHO, CompletableFuture is more elegant and has more capabilities.
Also, here you have a working example project.
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
}
I need to simulate a widget that shows purchases in real time.
To increase statistics, I want to supercharge real purchases with fake data, that needs to be emit in random interval.
All the events (real and fake ones) go to the message channel and get processed and then send to frontend.
So I need to come up with some service, that I can control (run and stop)
public class FakeDataGenerator {
private boolean run;
private Queue queue;
public void run() {
run = true;
while(run) {
queue.push(generateFakeOne())
TimeUnit.SECONDS.sleep(ThreadLocalRandom.current().nextInt(1, 30));
}
}
public void stop() {
run = false;
}
private Purchase generateFakeOne() {
// ... some faking logic
}
}
generator.stop();
where generator.run(); will start emitting events with random interval, and generator.stop(); will allow me to stop it any time
Is there any tool to accomplish such task? I'm not happy with using an infinite loop.
If you are using spring-boot why don't try using just #Scheduled(fixedDelay = 1000) annotation example
Example
#Scheduled(fixedDelay = 1000)
public void scheduleFixedDelayTask() {
System.out.println(
"Fixed delay task - " + System.currentTimeMillis() / 1000);
}
Use some of Spring Executor and give it a task to execute. You can control it by the executor reference
In a loop i need to make some checks, performed actually in some another verticle. In each iteration of my loop i need to check the response code, returned from those verticle and make some decision accordingly. In some other words i need to stop the execution of my loop and somehow wait till asynch. call returns. But such execution stop violates the vert.x philosophy, which states that main thread execution should be never stopped. How can i do it in the scope of Vert.x? So far i don't know how to do this. Any suggestions/code samples/urls to smth. like a solution would b highly appreciated.
Thanks!
When working with Vert.x you need to think less in terms of loops, and more in terms of callbacks.
You should use eventBus to communicate between vertices.
Let's say that what you want is something similar to this pseudocode:
for (int i = 0; i < 4; i++) {
int result = getVerticleResult();
System.out.println(result);
}
So, just a very basic example
class LooperVerticle extends AbstractVerticle {
private int i = 4;
#Override
public void start() throws Exception {
doWork();
}
private void doWork() {
vertx.eventBus().send("channel", "", (o) -> {
if (o.succeeded()) {
System.out.println(o.result().body());
i--;
if (i > 0) {
doWork();
}
}
});
}
}
class WorkerVerticle extends AbstractVerticle {
#Override
public void start() throws Exception {
vertx.eventBus().consumer("channel", (o) -> {
// Generate some random number
int num = ThreadLocalRandom.current().nextInt(0, 9);
// Simulate slowness
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
o.reply(num);
});
}
}
To test:
public class EventBusExample {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new LooperVerticle());
vertx.deployVerticle(new WorkerVerticle());
}
}
I think you need to use FutureTask and store them in a Collection and use FutureTask.get() to retrieve the result when needed which is a blocking call.
It sounds like a use case for reactive steam processing.
In general such problem could be solved using 2 parties:
a producer that executes tasks and returns asynchronous results
a handler that subscribes to results and performs another tasks
There is a way to configure producer to perform tasks only when there is a subscriber. And on other side subscriber can decide to unsubscribe from producer on some condition.
I'm not familiar with vertx capabilities for reactive streams. But I would start from RxJava integration
http://vertx.io/docs/vertx-rx/java/
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());
}
}