'HttpURLConnection getResponseCode() API call gets stuck for ~30 mins on POST request and then returns IOException
I'm facing issue of my client app getting hanged for long duration while trying to send a POST request. My connection timeout is 5sec and read timeout is 240 sec. But, the request gets stuck in wait state for approx 30min. before returning below IOException.
SyncRESTClient|processRequest|Received IO Exception for requestURI[http://172.50.32.79:8002/BatchWrite/1/1], Exception:
java.io.IOException: Error writing to server
at sun.net.www.protocol.http.HttpURLConnection.writeRequests(HttpURLConnection.java:666)
at sun.net.www.protocol.http.HttpURLConnection.writeRequests(HttpURLConnection.java:678)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1534)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at SyncRESTClient.processRequest(SyncRESTClient.java:62)
POST Request Size: ~2MB
Note:
- The issue is intermittent i.e. out of 100 requests, it may/may not occur once.
- We have also sent requests with larger size than 2MB and they also got processed.
Test Environment:
- Both client and server are on different machines with 100Mbps connectivity
Code Snippet:
HttpURLConnection connObj = null;
URL myurl = null;
try {
myurl = new URL(requestInfo.getUri());
connObj = (HttpURLConnection) myurl.openConnection();
connObj.setRequestProperty("Accept", "*/*");
// set connect timeout
if(0 < requestInfo.getConnectTimeout()) {
connObj.setConnectTimeout(requestInfo.getConnectTimeout());
}
// set request timeout
if(0 < requestInfo.getRequestTimeout()) {
connObj.setReadTimeout(requestInfo.getRequestTimeout());
}
switch(requestInfo.getMethod()) {
case GET:
connObj.setRequestMethod("GET");
break;
case POST:
connObj.setRequestMethod("POST");
connObj.setRequestProperty("Content-Type", "application/octet-stream");
connObj.setDoOutput(true);
break;
}
//connObj.setRequestProperty("User-Agent", "Mozilla/5.0");
if(RESTRequestInfoMethodTypes.POST == requestInfo.getMethod()) {
try (DataOutputStream wr = new DataOutputStream(connObj.getOutputStream())) {
wr.write(requestInfo.getData(), 0, (int)requestInfo.getDataLength());
}
}
rv = 0;
int statusCode = connObj.getResponseCode(); <--- STUCK HERE
responseInfo.setHttpStatusCode(statusCode);
if(HttpURLConnection.HTTP_OK == statusCode) {
try (InputStream is = connObj.getInputStream()) {
//byte[] arr = is.readAllBytes(); // Available since Java9
//byte[] arr = is.readNBytes(Integer.MAX_VALUE); // Available since Java11
/*byte[] arr = new byte[is.available()];
int length = is.read(arr);
responseInfo.setData(arr);
responseInfo.setLength(length);*/
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384]; // 16K buffer allocation for reading
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
responseInfo.setData(buffer.toByteArray());
responseInfo.setLength(buffer.size());
buffer.close();
buffer = null;
}
} else {
try (InputStream is = connObj.getErrorStream()) {
if(null != is) {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384]; // 16K buffer allocation for reading
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
responseInfo.setData(buffer.toByteArray());
responseInfo.setLength(buffer.size());
buffer.close();
buffer = null;
}
}
}
} catch (MalformedURLException e) {
log.error("SyncRESTClient|processRequest|Received malformed exception for requestURI[" + requestInfo.getUri() + "], Exception: " , e);
rv = -1;
} catch(java.net.SocketTimeoutException e) {
log.error("SyncRESTClient|processRequest|Request timed out for requestURI[" + requestInfo.getUri() + "] after [" + (System.currentTimeMillis()-startTime) + " ms], Exception: " + e);
rv = -1;
responseInfo.setHttpStatusCode(HttpURLConnection.HTTP_CLIENT_TIMEOUT);
} catch(java.net.ConnectException e) {
log.error("SyncRESTClient|processRequest|Failure while connecting to requestURI[" + requestInfo.getUri() + "], Exception: " + e);
rv = -1;
responseInfo.setHttpStatusCode(HttpURLConnection.HTTP_UNAVAILABLE);
} catch(IOException e) {
log.error("SyncRESTClient|processRequest|Received IO Exception for requestURI[" + requestInfo.getUri() + "], Exception: " , e);
rv = -1;
} catch(Exception e) {
log.error("SyncRESTClient|processRequest|Exception while processing request[" + requestInfo.getUri() + "]: " , e);
rv = -1;
} catch(OutOfMemoryError e) {
log.error("SyncRESTClient|processRequest|Received OutOfMemoryError while processing request[" + requestInfo.getUri() + "]. Error: " , e);
rv = -1;
} finally {
if(null != connObj)
connObj.disconnect();
connObj = null;
myurl = null;
}
New Update:
Found the reason behind the socket getting hanged. It was observed that packet drops occurred between client and server machine for the session. Due to these packet drops, client was unable to detect that server has closed the connection by sending fin-ack packet. It resulted in client still being in established state waiting for communication.
Steps to replicate the issue:
Start sending data from client to server
While data is being transmitted, run below linux command on client machine to drop packets received from server:
iptables -I INPUT -i "interface" -s "serverMachineIP" -j DROP
Eg: iptables -I INPUT -i eth0 -s 172.50.31.10 -j DROP
Above steps will result in client getting stuck for long duration.
New Question: What should be done at client so that request can timeout in given interval of time?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
