I've been doing this tutorial about how to return async callable object. It works as intended. But while the first request sleeps for 5 seconds I get the second request, controller waits for the previous request to finnish before handling the second one.
How to make controller handle immediately every request and make sleeping in a background?
#Edit
Example:
Imagine a situation, that my controller needs to make a request to external api and based on its response it should send his own response. External api call takes lets say 2 seconds. I want users of my application to wait only that 2,5 seconds and not be placed in queue, because the controller can handle only one request at a time.
Is REST controller multithreaded?
REST controller is multithreaded as the DisptcherServlet handles multiple requests from the clients concurrently and serves using the respective controller methods. You can refer the request handling flow here
How to make controller handle immediately every request and make
sleeping in a background?
You can do that by returning Callable<String> in the Spring controller method as shown below:
#Controller
public class MyController {
#RequestMapping(value="/sleep")
public Callable<String> myControllerMethod() {
Callable<String> asyncTask = () -> { try {
System.out.println(" WAITING STARTED:"+new Date());
Thread.sleep(5000);
System.out.println(" WAITING COMPLETED:"+new Date());
return "Return";//Send the result back to View Return.jsp
} catch(InterruptedException iexe) {
//log exception
return "ReturnFail";
}};
return asyncTask;
}
Output:
WAITING STARTED: Thu Nov 24 21:03:12 GMT 2016
WAITING COMPLETED: Thu Nov 24 21:03:17 GMT 2016
After this, the view will be returned "Return.jsp" page.
Here, the controller method will be running in a separate thread (releasing the actual servlet thread) and once the task is completed the Result will be sent back again to the client (View etc..).
P.S.: You need to add #EnableAsync as part of your application configuration, you can look here on this.
What you want to do is what it is supposed to be done in the first example of the tutorial you linked:
#RequestMapping(value = "/block", method = RequestMethod.GET, produces = "text/html")
public String executeSlowTask() {
logger.info("Request received");
Thread.sleep(5000);
logger.info("Servlet thread released");
return result;
}
This blocks the calling thread and waits till it is done. If you call from a different HTTP session, it will be another thread, so it will be a new 5 seconds wait (not affected by the first one).
Threads are linked to HTTP calls as long as there are threads available in the pool (configuration of the tomcat server).
It is not the case that the controller will block all subsequent calls while busy. It is multithreaded.
Related
I have the following controller method:
#Transactional
#PostMapping(path = "/add")
#Secured({Constants.ADMIN, Constants.DATAMANAGER})
public DeferredResult<ResponseEntity> addNewCitizens(
#RequestBody List<Citizen> citizens) {
// Time out in 30 minutes
DeferredResult<ResponseEntity> output = new DeferredResult<>((long) (1000 * 60 * 30));
ForkJoinPool.commonPool().submit(() -> {
// Long operation...
output.setResult(new ResponseEntity(HttpStatus.OK));
}
return output;
}
The method usually receives a lot of data and uses it to update my database. For the data I'm testing with right now it takes 3-4 minutes.
For some reason, when it takes a while for it to process the request, it starts all over when it has finished running once, as if it received another request. The Angular front end application from which i sent the request never receives a response in this case. For fast requests it works perfectly. Also, I checked the network tab in Chrome and I can only see one request getting sent to the endpoint in there.
What could be causing this, and what can I do to fix it? Thanks!
Additional info: It only happens when I deploy the service to a remote server - not when I test on my local machine...
For the last week I read documentation about vertx. What i don't get it's how vertx handlers are work? For example
public class Client extends AbstractVerticle{
#Override
public void start() throws Exception {
final HttpClient httpClient = this.vertx.createHttpClient();
this.vertx.setPeriodic(1000, handler->{
httpClient.getNow(8080, "localhost", "/", responseHandler -> {
System.out.println("response");
});
});
}
}
And server is:
public class JdbcVertx extends AbstractVerticle{
#Override
public void start() throws Exception {
JDBCClient client = JDBCClient.createNonShared(this.vertx, new JsonObject()
.put("url", "jdbc:postgresql://localhost:5432/test")
.put("user", "user")
.put("password", "password")
.put("driver_class", "org.postgresql.Driver")
.put("max_pool_size", 30));
this.vertx.createHttpServer()
.requestHandler(r -> {
client.getConnection(handler -> {
final SQLConnection connection = handler.result();
connection.execute(execute(), hndlr -> {
connection.close(closehndlr -> {
r.response().putHeader("content-type", "text/html").end("Response");
});
});
});
}).listen(8080);
}
private String execute(){
return "insert into rubish (name) values ('test')";
}
}
(P.S i know that i firstly should to check if handler is succeded and then make some action but i remove this checking to simplify code and also from official docs if there is no any response during 30 sec there will be an exception in handler)
From the code above, client send request each second and doesn't wait for response , but it has a handler that will be executed when response was comming.
'JdbcVertx' listen on port 8080 , get request, make insertion to db with sleep for example 3 s (i put 1_000_000 rows to db and create index to slow down insertion time) and then send response, therefore each request is non blocking.
As i know , vertx has only one thread named EventLoop event loop from jdbcVertx get reqests but doesn't return response immediately , instead it put a handler that will be executed when db insertion was succeed. How event loop know when IO action is done. I think that it use somthing like this
if(Thread.currentThread().getState != 'blocked' && sec != 30){
this.object.getHandler().execute();
} else if(sec == 30){
Thread.currentThread.inerrupt();
} else{
sec++;
}
But we have only one thread, and when we have blocking call it doesn't has a thread, only handler.
The problem is , how event loop know when blocking operation is ended and it's time to execute handler
But we have only one thread, and when we have blocking call it doesn't has a thread, only handler. How it work , and why do we need to use Worker Verticle if we can use handlers instead?
The handlers are just actions triggered upon receipt of an eventbus message or an http call. They are not designed to handle scalability for you. If you only use handlers and if your actions starts to take a long time or if you have any increase in the number of requests, you will block the eventloop of your verticle and will have a lot of Thread xxxx has been blocked warns.
To answer on how handler works and why the event loop doesn't wait the end of a handler to start another, according to this : https://vertx.io/docs/vertx-core/java/#_reactor_and_multi_reactor
Instead of a single event loop, each Vertx instance maintains several event loops. By default we choose the number based on the number of available cores on the machine, but this can be overridden.
This means a single Vertx process can scale across your server, unlike Node.js.
We call this pattern the Multi-Reactor Pattern to distinguish it from the single threaded reactor pattern.
But that's not enough to handle all scalability and thread blocking problematics for you in my opinion, you schould read this too : https://vertx.io/docs/vertx-core/java/#golden_rule
There are many ways to design verticles but you have to stay as non-blocking as possible. In my opinion, using vert.x with a traditional blocking approach (like blocking restfull endpoints for example) is not relevant.
Personally I'd design my verticles as follows :
verticle A : which expose a restfull endpoint and take a callback url (whatever the action GET/POST/PUT/PATCH/DELETE). The verticle always respond a 202 Accepted immediatly without result and send a message in the eventbus to a verticle B.
verticle B : get the message, do the action (eventually invoke other verticles asynchronously with the eventbus and waiting the replies) and reply invoking the callback url.
I'd avoid to use worker verticle or the executeBlocking method or even creating a pool of thread. I'd privilege multiplying the instances of my verticles B (in seperate pids) that listen to the same eventbus cluster (and eventually verticle A with a http reverse proxy). We can even imagine having a variable number of verticle B instances (in seperate pids) depending on the number of requests in real time.
P.S : sometimes I use a more powerfull message broker tool like Apache Kafka instead of the native eventbus (when I need to respect a sort of message, or when I need to replay some messages).
Answering the question:
how event loop know when blocking operation is ended and it's time to execute handler?
According to the non-blocking model, the event-loop upon the call
connection.execute( execute(), hndlr )
spawns a new thread, executes your blocking piece of code and upon it's completion (something like Thread.join()) invokes the hndlr callback in the event-loop thread. Thus the main loop doesn't get blocked although the blocking code can be executed.
In my application I need to implement functionality which ensure that if client makes GET request, application will hold this request until some change happen in database and also be possible to set maximal holding time.
For example:
User makes GET request and request will hold for 20 seconds. If during these 20 s something changes in database, application release this request with required data, else application hold request for 20s.
I decide to use long polling. In my application I am using Spring Boot as well. Can you tell me if it possible do it with Spring or should I add some another library for that?
I also found Spring Scheluder for holding request for some interval, but problem is that, scheluder is not allowed for methods with parameters, but I need fetch data by specific user, so at least user's id should be passed. Also I am not sure if it possible to manually release this scheluder when it is needed.
Thanks for advice!
For long pulling request you can use DeferredResult. when you return DeferredResult response, request thread will be free and this request handle by worker thread. Here is one example:
#GetMapping("/test")
DeferredResult<String> test(){
Long timeOutInMilliSec = 100000L;
String timeOutResp = "Time Out.";
DeferredResult<String> deferredResult = new DeferredResult<>(timeOutInMilliSec,timeOutResp);
CompletableFuture.runAsync(()->{
try {
//Long pooling task;If task is not completed within 100 sec timeout response retrun for this request
TimeUnit.SECONDS.sleep(10);
//set result after completing task to return response to client
deferredResult.setResult("Task Finished");
}catch (Exception ex){
}
});
return deferredResult;
}
In this request give response after waiting 10 sec. if you wait more than 100 sec you will get timeout response.
Look at this.
I use REST API based system, in which there are some requests that take long time to complete. I want to give user an option to cancel the request.
First, support
POST /requests
which will return a reference to the status of the request
{
"id": 1234,
"self"": "/requests/1234"
"status": "Running"
}
Then add support for
PUT /requests/1234
{
"status": "Canceled:"
}
That will let clients cancel a request if it hasn't finished yet. If the request is to create some other kind of resource, then instead of POST /requests, do POST /myResource, but still return the status object with the pointer to /requests in the response.
Clients can then poll /requests to see when the request is complete.
Firstly you need to use multiple threads because your program will be on hold while it is sending the request so you cannot click on something until it is back from hold.
Create a thread which calls the rest API in background without hanging the overall application and terminate that thread on click of a button.
note for terminating the thread you need to use stop function which is depreciated now because you cannot interrupt the thread or check a Boolean during the process.
#Deprecated
public final void stop()
Alternatively, you can use Maximum Time for a HTTP Request call by
HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
_For all scenario
Make thread pool method
executorService = Executors.newFixedThreadPool(1);
Put your logical method in callable store in future object
Future<Boolean> futureObjects = executorService.submit(newCallable<Boolean>() { ....call your logical method which you going run in multiple thread....});
3.Gets your results future object
return (futureObjects != null)
? futureObjects.get(timeout, TimeUnit.SECONDS)
: null;
The default waits until getting separate calls response.
4.IN between calling multiple threads requesting user want to stop or break their multiple thread calls then simply check executor is not terminated then terminate immediately
if (executorService != null && !executorService.isTerminated(){
executorService.shutdownNow();
}
some premise changed on my original question posted in inter-thread communication between java application and jax-ws web service ( i am also simplifying the question to make it simpler to understand (and hence get answered)... hope that's ok with the moderators.)
a web service thread (THREAD-1) places a request on a socket and goes to sleep waiting for the response. another listener thread (THREAD-2) (running as a separate web application, once it receives the response) has to wake up THREAD-1 out of its sleep.
how do i do that ( in a push notification way)?
They both have access to a database table. The THREAD-1 can put its unique id in the table before it goes to sleep. THREAD-2, once it receives the response and determines it belongs to THREAD-1, it updates the appropriate row in the database table. Now THREAD-1 can do polling (at regular intervals) on the database table to check if the response has arrived.
But I am looking to do it in a push-notification way. The THREAD-1 should be notified right away when the response has arrived without it having to poll every few seconds.
If your backend request completes quickly and you won't have a torrent of client requests to handle, you can have the web service wait for a response over the same socket it just opened. It can block waiting to read the response.
However, if you have access to Servlet 3.0 (e.g. Tomcat 7), you can use asynchronous HTTP requests. It allows you to release the thread handling the web service client back into the pool without responding to the client's request. When a response message arrives from the backend service, the grabs the appropriate web service client request from the servlet container and sends the final response back to the web service client.
Well, as the comment suggest: better don't try to implement this yourself. However, basically you could use standard Java thread-synchronization with wait()/notify()
Thread-1 sets of remote call to Thread-2 together with a unique call-ID.
Thread-1 does now wait() on a synchronization object (instead of sleep())
Thread-2 does the work and to return the result it calls some remote callback method in the JVM Thread-1 resides in - call-ID is passed together with the result
The callback method on the Thread-1 side makes the result available via call-ID and wakes up all waiting threads by means of notifyAll()
Threads incl. Thread-1 check if their result arrived, if yes they continue to work if no the wait() again.
Pseudo code for the Thread-1 side:
HashMap<String, Object> results;
// Called by Thread-1 to access Thread-2
public void doIt() {
String callId = "aUniqueCallId";
Object result = null;
remoteCallToThread2(callId);
synchronized(results) {
while((result = results.remove(callId)) == null) {
results.wait();
}
}
doSomethingWith(result);
}
// Called remotely by Thread-2 when result is available
public void callback(String callId, Object result) {
synchronized(results) {
results.put(callId, result);
results.notifyAll();
}
}
Of course this is just the basic idea and can not be used as such, there's a lot of stuff to be considered here.