Во-первых, немного предыстории. Есть рабочий, который раскрывает / разрешает кучу коротких URL:
http://t.co/example -> http://example.com
Итак, мы просто следим за перенаправлениями. Вот и все. Мы не читаем данные из соединения. Сразу после того, как мы получили 200, мы возвращаем конечный URL и закрываем InputStream.
Теперь сама проблема. На рабочем сервере один из потоков преобразователя зависает внутри вызова InputStream.close()
:
"ProcessShortUrlTask" prio=10 tid=0x00007f8810119000 nid=0x402b runnable [0x00007f882b044000]
java.lang.Thread.State: RUNNABLE
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.skip(BufferedInputStream.java:352)
- locked <0x0000000561293aa0> (a java.io.BufferedInputStream)
at sun.net.www.MeteredStream.skip(MeteredStream.java:134)
- locked <0x0000000561293a70> (a sun.net.www.http.KeepAliveStream)
at sun.net.www.http.KeepAliveStream.close(KeepAliveStream.java:76)
at java.io.FilterInputStream.close(FilterInputStream.java:155)
at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.close(HttpURLConnection.java:2735)
at ru.twitter.times.http.URLProcessor.resolve(URLProcessor.java:131)
at ru.twitter.times.http.URLProcessor.resolve(URLProcessor.java:55)
at ...
После краткого исследования я понял, что skip()
вызывается для очистки потока перед его отправкой обратно в пул подключений (если включена поддержка активности?). До сих пор не понимаю, как избежать этой ситуации. Более того, я сомневаюсь, что в нашем коде плохой дизайн или есть проблема в JDK.
Итак, вопросы:
- Можно ли избежать зависания на
close()
? Например, обеспечьте разумный тайм-аут. - Можно ли вообще избежать чтения данных из соединения? Помните, мне нужен только конечный URL. На самом деле, я думаю, я вообще не хочу, чтобы
skip()
назывался ...
Обновление:
KeepAliveStream, строка 79, close()
метод:
// Skip past the data that's left in the Inputstream because
// some sort of error may have occurred.
// Do this ONLY if the skip won't block. The stream may have
// been closed at the beginning of a big file and we don't want
// to hang around for nothing. So if we can't skip without blocking
// we just close the socket and, therefore, terminate the keepAlive
// NOTE: Don't close super class
try {
if (expected > count) {
long nskip = (long) (expected - count);
if (nskip <= available()) {
long n = 0;
while (n < nskip) {
nskip = nskip - n;
n = skip(nskip);} ...
Мне все больше и больше кажется, что в самом JDK есть ошибка. К сожалению, воспроизвести это очень сложно ...
HEAD
вместоGET
? - person artbristol   schedule 17.01.2013Location:
и без тела.t.co
, например, возвращаетContent-Length: 0
. Так нельзя просто прочитать весь поток (из 0 байтов) перед его закрытием? - person artbristol   schedule 18.01.2013setInstanceFollowRedirects(false)
? - person artbristol   schedule 18.01.2013HEAD
. Проблема в том, что нам тоже нужно следить за редиректами для обычных сайтов. Некоторые из них по той или иной причине выполняют редиректы. Так что в общем случае у вас в итоге будетGET
для какого-то обычного сайта. И кажется, что для некоторых из этих сайтов JDK ведет себя странно. - person Shcheklein   schedule 18.01.2013false
и следить за ними вручную. Но воспроизвести это зависание очень-очень сложно (за год я вижу второй случай). Чего вы ждете от этого изменения? Почему это должно влиять на поведениеclose()
? - person Shcheklein   schedule 18.01.2013