How do I simulate a client aborting request? - java

I'm tasked with solving a reported bug, where the logs show a
org.apache.catalina.connector.ClientAbortException: java.io.IOException
...
Caused by: java.io.IOException
at org.apache.coyote.http11.InternalAprOutputBuffer.flushBuffer(InternalAprOutputBuffer.java:205)
There are several questions here about the ClientAbortException, and my understanding from reading them, and also the Tomcat javadoc, is that the exception is thrown by Tomcat when the client aborts the HTTP request.
I'm having trouble reproducing the error. How can I simulate a client abort?
What I've tried
Adding a Thread.sleep(10000) in the request handler, and then closing the browser while the request is running - but that doesn't do it.
Cancelling the HTTP request from the client side using this technique with angular.

Ok, with a bit of experimenting - I've found a way to do it.
What it looks like - is that if an http request is cancelled/timed out by the client while the server is writing/flushing the output then the error will be thrown. (NB. It appears as if the size of the response also matters - see my note at the end).
There are three things that can happen:
Condition 1: Server writes and flushes output before client timeouts.
Response is sent back to client.
Condition 2: Client times out before server writes and flushes output.
Client does not receive response, no server error.
Condition 3: Client times out while server is writing output.
Client does not receive response. Server throws ClientAbortException (java.io.IOException).
To simulate these three conditions, we play with three variables:
The time client takes to timeout
Time server burns getting its result.
The size of the server response.
Here is the test code to simulate it:
Server side (This is a Spring MVC controller).
#RequestMapping(value = { "/debugGet" }, method = RequestMethod.GET)
#ResponseBody
public List<String> debugGet(#RequestParam int timeout, int numObjects) throws InterruptedException {
Thread.sleep(timeout);
List<String> l = new ArrayList<String>();
for (int i =0; i< numObjects; i++){
l.add(new String());
}
return l;
}
Client side (Angular)
this.debugGet = function(server, client, numObjects){
var httpProm = $http({
method: "GET",
url: "debugGet",
timeout: client,
params : {
timeout: server,
numObjects: numObjects}
});
httpProm.then(function(data){
console.log(data);
}, function(data){
console.log("error");
console.log(data);
});
};
Using this I can simulate the three conditions with the following params:
Client Timeout Server Burn Time Num Strings
Condition 1: 1000 900 10000
Condition 2: 1000 2000 100
Condition 3: 1000 950 10000
NB It appears as if the size of response also matters.
For example:
Client Timeout Server Burn Time Num Strings
Condition 2: 1000 2000 100
Condition 3: 1000 2000 10000
Here for the 10000 Strings, we get the java.io.IOException even though the flush occurs well after the client has timed out, whereas it doesn't for the 100 Strings.

Related

Spring - server.connection-timeout not working

In my application.properties file I have...
server.port=8086
server.connection-timeout=15000
I know that the file is being loaded correctly because the server is running on port 8086.
In the application I have a RestController
#RestController
class TestController {
#GetMapping()
fun getValues(): ResponseEntity<*> {
return someLongRunningProcessPossiblyHanging()
}
}
When I call the endpoint, the request never times out, it just hangs indefinitely.
Am I missing something?
NOTE: I've also been informed that Tomcat uses this field in minutes, not milliseconds (rather unusual choice IMO). I've tried setting this to server.connection-timeout=1 denoting 1 minute, but this didn't work either.
NOTE: I don't want another HTTP request to cause the previous request to time out, I want each HTTP request to timeout of it's own accord, should too much time elapse to serve the request.
connection-timeout does not apply to long running requests. It does apply to the initial connection, when the server waits for the client to say something.
Tomcat docs (not Spring Boot) define it as The number of milliseconds this Connector will wait, after accepting a connection, for the request URI line to be presented [...]
To test the setting server.connection-timeout=4000 I connect using netcat and I don't send any HTTP request/headers. I get:
$ time nc -vv localhost 1234
Connection to localhost 1234 port [tcp/*] succeeded!
real 0m4.015s
user 0m0.000s
sys 0m0.000s
Alternatives
1) Async
From brightinventions.pl - Spring MVC Thread Pool Timeouts:
In Spring MVC there is no way to configure a timeout unless you use async method. With async method one can use spring.mvc.async.request-timeout= to set amount of time (in milliseconds) before asynchronous request handling times out.
I've set spring.mvc.async.request-timeout=4000 and I get a timeout in the browser with this:
#GetMapping("/test-async")
public Callable<String> getFoobar() {
return () -> {
Thread.sleep(12000); //this will cause a timeout
return "foobar";
};
}
See Spring Boot REST API - request timeout?
2) Servlet filter
Another solution would be to use a servlet filter brightinventions.pl - Request timeouts in Spring MVC (Kotlin):
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
val completed = AtomicBoolean(false)
val requestHandlingThread = Thread.currentThread()
val timeout = timeoutsPool.schedule({
if (completed.compareAndSet(false, true)) {
requestHandlingThread.interrupt()
}
}, 5, TimeUnit.SECONDS)
try {
filterChain.doFilter(request, response)
timeout.cancel(false)
} finally {
completed.set(true)
}
}
3) Tomcat Stuck Thread Detection Valve?
Tomcat has a Stuck Thread Detection Valve but I don't know if this can be configured programmatically using Spring Boot.
From the official docs:
server.connection-timeout= # Time that connectors wait for another HTTP request before closing the connection. When not set, the connector's container-specific default is used. Use a value of -1 to indicate no (that is, an infinite) timeout.
Another ref, also mentions the same. It should work for you.
When I call the endpoint, the request never times out, it just hangs indefinitely.
server.connection-timeout isn't a request timeout. It is a timeout for idle connections, i.e. those that have already had a request/response pair and on which the server is now awaiting a second request. It is essentially a server-side read timeout.

Using Jsoup connect() in a loop. The first request is always much slower than all other subsequent ones

I'm creating a small app to measure how long it takes an HTML document to load, checking every x number of seconds.
I'm using jsoup in a loop:
Connection.Response response = null;
for (int i = 0; i < totalGets; i++) {
long startTime = System.currentTimeMillis();
try {
response = Jsoup.connect(url)
.userAgent(USER_AGENT) //just using a Firefox user-agent
.timeout(30_000)
.execute();
} catch (IOException e) {
if (e.getMessage().contains("connect timed out")) {
System.out.println("Request timed out after 30 seconds!");
}
}
long currentTime = System.currentTimeMillis();
System.out.println("Response time: " + (currentTime - startTime) + "ms" + "\tResponse code: " + response.statusCode());
sleep(2000);
}
The issue I'm having is that the very first execution of the jsoup connection is always slower than all subsequent once, no matter what website.
Here is my output on https://www.google.com
Response time: 934ms Response code: 200
Response time: 149ms Response code: 200
Response time: 122ms Response code: 200
Response time: 136ms Response code: 200
Response time: 128ms Response code: 200
Here is what I get on http://stackoverflow.com
Response time: 440ms Response code: 200
Response time: 182ms Response code: 200
Response time: 187ms Response code: 200
Response time: 193ms Response code: 200
Response time: 185ms Response code: 200
Why is it always faster after the first connect? Is there a better way to determine the document's load speed?
1.
Jsoup must run some boiler plate code before the first request can be fired. I would not count the first request into your measurements, since all that initialization will skew the first request time.
2.
As mentioned in the comments, many websites cache responses for a couple of seconds. Depending on the website you want to measure you can use some tricks to get the webserver to produce a fresh site each time. Such a trick could be to add a timestamp parameter. Usually _ is used for that (like http://url/path/?pameter1=val1&_=ts). Or you could send along no cache headers in the HTTP request. however, none of these tricks can force a webserver to behave the way you want it. So you can wait longer than 30 seconds in between each request.
I think that in addition to #luksch points there is another factor, I think Java is keeping connection alive for a few seconds, maybe saving time in protocol trips.
If you use .header("Connection", "close") you'll see more consistent times.
You can check that connections are kept alive with a sniffer. At least I can see port numbers (I mean source port, of course) reused.
EDIT:
Another thing that may add time to first request is DNS lookup ...
Another potential reason is JVM is doing JIT optimization in background which turns java byte code into native instructions to improve speed.
The first time you run the code it's slow because the code haven't been optimized. The following rounds are faster because the optimization is already done.
Parsing html page is a pretty computationally intensive job.

Spring MVC, best practice how to often polling server

Im working on web application using the following stack of technologies: Spring, Hibernate, JSP. I have a task to make one of user social element - messages. As standard of implementation message system i take facebook system. On of the problem i faced is a polling server every 1-5 seconds (what period i have to take?) to retrieve an information about unread messages. Also i want to polling server to retrieve new messages at conversation page (like a chat). What i did:
Example code of get count unread messages.
Server side:
#RequestMapping(value = "/getCountUserUnreadMessages", method = RequestMethod.POST)
public #ResponseBody Callable<Integer> getCountUserUnreadMessages(#ActiveUser final SmartUserDetails smartUserDetails) {
// TODO add additional security checks using username and active user
return new Callable<Integer>() {
#Override
public Integer call() throws Exception {
Integer countUserUnreadMessages = messageService.findCountUserUnreadMessages(smartUserDetails.getSmartUser());
while (countUserUnreadMessages == 0) {
Thread.sleep(1000);
countUserUnreadMessages = messageService.findCountUserUnreadMessages(smartUserDetails.getSmartUser());
}
return countUserUnreadMessages;
}
};
}
Client side:
(function poll(){
setTimeout(function () {
$.ajax({
type: "post",
url: "/messages/getCountUserUnreadMessages",
cache: false,
success: function (response) {
$("#countUnreadMessages").text(response);
}, dataType: "json", complete: poll, timeout: 1000 });
}, 3000);
})();
So client send a request to retrieve count unread messages every second with a timeout in 3 seconds (is it good decision?).
But i think that is the worst callable code ever :-P
Tell me how to do better? What technique use?
Additional information:
Yeah, i supposed that it would be highload, many users service in the Internet.
Try Spring 4 WebSocket support:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html
WebSockets support full duplex communication over a dedicated TCP connection that you establish over HTTP.
If you are expecting this application to have to scale at all I would make that timing interval more like every 30 - 90 seconds. Otherwise you are basically going to be designing your own built in DOS attack on your self.
You might look into Spring Sockets. It sounds like it's long polling option might work better for you.

Google App Engine: URLFetch maximum timeout is 250 seconds from task and not 600 seconds (10min)

According to the official docs, the timeout for a http request via URLFetch on Google App Engine is 10 minutes if issued from a task:
https://developers.google.com/appengine/docs/java/urlfetch/overview#Quotas_and_Limits
Unfortunately I'm experiencing a 250 seconds (4:10 min) timeout no matter what
I've setup as simple php test script running on Apache (but I've tested it with Lighttpd as well) that I'm calling from GAE that just waits 300 seconds and then returns
Http hook:
echo "Starting to wait\n";
$waited = 0;
while($waited < 300) {
sleep(5);
$waited += 5;
echo "Waited so far $waited seconds\n";
}
echo "all done\n";
The call always fails after approx 250 seconds and throws the following error in the GAE logs
IOException : Could not fetch URL ...
which isn't even a timeout related exception
On the other side the web server records a successful call with http return code 200
The Java code I'm using to make the call is as follows
HTTPRequest httpReq = new HTTPRequest(new URL(http://example.com/very-slow.php), HTTPMethod.GET, FetchOptions.Builder.allowTruncate().doNotValidateCertificate().setDeadline(3600d));
HTTPResponse resp = null;
try {
Future<HTTPResponse> futureResp = urlService.fetchAsync(httpReq);
log.info("Aync Call request lodged, waiting for a response");
resp = futureResp.get();
log.info("Aync Call completed");
} catch(Throwable th) {
log.warning("URLFetch execution error: " + th.getMessage());
}
I've tried playing around with the setDeadline method specifying all sorts of different values without much luck. If I specify a value lower than 250 seconds, it's used and a timeout exception is thrown. Anything above 250 seconds is ignored and a generic IOException is thrown instead.
I'm pretty sure this looks like a GAE bug and after looking at the bug list on google code I freaked out at how many unresolved bugs are just pending there for years...
Very disappointed by Google App Engine at this stage...
Update
Only the production environment is affected. On the development server I experience no problems. Timeouts are generally not enforced on the dev server though...
I've tried with both the sync and async URLFetch methods: same result.
I've tried with both the low-level GAE-proprietary URLFetch or the java.net URLConnection objects: same result

long polling using JSON not working

I am trying to build chat application with long polling mechanism on Google app engine server.
HTTPRequest has default time out of 30 seconds, so I am sending polling request to server every 28 seconds if there is no update from server (so that I wont miss any message from other clients).
First request gets registered, but second request sent after 28 seconds is not reaching server.
function loadPage(query){
$.get({ url: query, success: function(events){
updated = 1;
//events data processing
createServerChannel();
});
}
function createServerChannel(){
var query='/ChatController?&user='+userName+'&sessionName='+sessionName+'&register=true';
loadPage(query);
updated = 0;
setInterval(function() { poll(query); }, 28000);
};
function poll(query){
if(updated==0){
loadPage(query);
}
}
I am using thread.wait() for request to wait on server. Is there any way to consume first pending request when next request from same client is available.
Please help.
I think web sockets might be a better approach as this keeps a continuous connection open to the server and waits for the server to push data to the client.
http://www.html5rocks.com/en/tutorials/websockets/basics/

Categories

Resources