Thursday, September 10, 2009

Beware of openStream

Yesterday we discovered a bug where one of our projects hung and had to be CTRL-C'd. The culprit ended up being one line:
URL url = new URL("http://someurl")
InputStream is = url.openStream()//<---this one
The openStream method is actually shorthand for openConnection().getInputStream(). So it returns a newly instantiated URLConnection and calls getInputStream() on that. The problem is, which the API won't tell you (but is visible in the source) is that the default values for connectTimeout and readTimeout are 0. This means, if the connection/read fails, it will continue to try to connect/read forever. While we tested for the connection to be good before we began processing, getting from a URL caused it to hang when the service went down in the middle of processing. The solution was mentioned in this StackOverflow question. The solution lies in not creating the InputStream from URL, but from URLConnection and setting the timeouts:
int timeoutMS = 5000 // 5 secs
try {
  URL url = new URL("http://someurl")
  URLConnection conn = url.openConnection();
  conn.setConnectTimeout(timeoutMs);
  conn.setReadTimeout(timeoutMs);
  InputStream is = conn.getInputStream();
} catch (java.net.UnknownHostException uhe) {
    // something useful here
} catch (java.net.SocketTimeoutException ste) {
    // something useful here
}
Eric has posted about this as well (it was his project we learned this from).