Подтвердить что ты не робот

Что такое ошибки, не связанные с контейнером в tomcat?

В catalina.out журнале моего Tomcat7 появляется ошибка, вызванная сторонней библиотекой, которая начинается с:

INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately
java.net.SocketException: Broken pipe
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)

Что это означает, что ошибка возникла в неконтейнерном потоке?

Я попытался получить подобное сообщение журнала, выбросив исключение из нового Thread, порожденного из моего кода приложения, с чем-то вроде этого:

new Thread(){
    @Override
    public void run() {
        Integer.parseInt("boom");
    }
}.start();

но это приводит к

Exception in thread "Thread-28" java.lang.NumberFormatException: For input string: "boom"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:492)
    at java.lang.Integer.parseInt(Integer.java:527)
    at ...

Итак, вопрос: что это значит, когда я вижу журнал, похожий на тот, который указан сверху? Что это означает, что ошибка возникает в неконтейнерном потоке? Как я могу воссоздать это?

4b9b3361

Ответ 1

Что это означает, что ошибка произошла в неконтейнерном потоке?

Это происходит, если вы используете асинхронную обработку запросов JSP 3.0+.

В асинхронном режиме клиентский запрос принимается потоком "контейнер", который вызывает метод Servlet service(). Этот метод (или один из вспомогательных методов doXxxx) вызывает startAsync(), который создает запрос Runnable для запроса и отправляет его Исполнителю. Затем этот исполнитель обрабатывает запросы на рабочих потоках ( "неконтейнер" ).

(Более подробное объяснение того, что происходит в асинхронном режиме, в комплекте с примером, можно найти здесь.)

Во всяком случае, сообщение "INFO:" просто говорит, что исходное исключение было брошено в стек одного из рабочих потоков Исполнителя. Он создается, когда Tomcat решает отправить неудавшийся запрос обратно в поток контейнера, чтобы можно было выполнить очистку запроса.

В вашем примере, я подозреваю, что исходный SocketException был вызван обработкой запроса, так что клиент (например, пользовательский браузер) отсрочил запрос и закрыл сокет. Спустя некоторое время ваш сервер попытался написать ответ, и это не удалось, потому что соединение было закрыто.

Как я могу его воссоздать?

Я предполагаю, но вы должны иметь возможность воспроизвести это сообщение "INFO:", выбрасывая исключение в методе Runnable run(). Конечно, вы должны использовать асинхронный режим.

Ответ 2

Первый выпуск:

INFO: произошла ошибка при обработке в потоке, отличном от контейнера. Соединение будет немедленно закрыто

Ans:

Поток async.Stockticker разбился из-за не обработанной ISE. Это объясняет поведение. Исключение записывается только на консоль. Он не регистрируется в файлах журнала Tomcat. Это ошибка с обработкой ошибок для Tomcat. Это не регресс последних изменений. Он воспроизводится с помощью Tomcat 7.0.59.

Он уже исправлен в trunk 8.0.x (for 8.0.21 onwards) и 7.0.x (for 7.0.60 onwards). Итак, вы можете обновить версию tomcat. Тогда это информационное сообщение не будет показано.

Ссылка на ресурс:

Ошибка 57683 - Сбой при использовании асинхронного примера, вызванного прерванным запросом клиента



Вторая проблема:

java.net.SocketException: Сломанная труба

Решение-1:

Эта проблема возникает, когда мы пропустили, чтобы закрыть соединения, такие как URLConnection, и закрыть различные открытые потоки. Я хочу поделиться примером

До:

OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Lorem ipsum...");
out.close();

После того, как:

OutputStream os = urlConnection.getOutputStream();
OutputStream out = new BufferedOutputStream(os);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));
bw.write("Lorem ipsum...");
bw.close(); //This is must. If you miss to close, then "java.net.SocketException: Broken pipe" error comes
out.close();
os.close(); 

Решение-2:

Когда мы хотим загрузить тестирование на нашем сервере приложений, иногда возникает эта ошибка.

Данные берут long time to be generated, а инструмент тестирования нагрузки не wait for the large amounts of data достаточно длинный, после чего он закрывает соединение. Фактически низкая память заставляла приложение закрывать приемный сокет или вообще полностью выходить с тем же эффектом.

Если мы добавим дополнительную память в нашу JVM, тогда она решила проблему.

Решение-3:

Как @EJP предложил

Это вызвано записью на соединение, когда другой конец уже закрыл его.

Таким образом, у вас есть плохо определенный или реализованный протокол приложения. если это происходит, что-то не так с вашей спецификацией или реализацией протокола приложения, скорее всего, у вас даже нет соединения.

Если HTTP-приложение на стороне сервера получает исключения Broken Pipe, это означает, что клиентский браузер вышел из другой /t 28 обратно в историю/независимо. Просто забудьте об этом.

Ссылка на ресурс:

Если вы хотите воспроизвести эту ошибку, то этот учебник может вам помочь.



Третий выпуск:

Исключение в потоке "Thread-28" java.lang.NumberFormatException: для строка ввода: "стрела"

Эта ошибка возникает, когда вы пытались преобразовать/разбрать алфавитную строку в interger. Это обычная java-ошибка NumberFormatException.



UPDATE:

Как вы хотели знать, в каких случаях Tomcat решает зарегистрироваться это дополнительное сообщение при обнаружении исключения, которое было выброшено из приложение. Поэтому я кратко расскажу.

Для четкой концепции "INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately java.net.SocketException: Broken pipe", сначала я хочу поделиться с вами тем, что это проблема сокета. Есть 6 SocketEvent в tomcat. Они OPEN_READ, OPEN_WRITE, STOP, TIMEOUT, DISCONNECT and ERROR. Они встречаются для каждого сокета, которые требуют дальнейшей обработки контейнером. Обычно эти события инициируются реализацией сокета, но они также могут запускаться контейнером.

Событие сокета "ОШИБКА":

Произошла ошибка в потоке, отличном от контейнера, и обработка должна была вернуться в контейнер для любой необходимой очистки. Примеры того, где это используется, включают:

  • от NIO2, чтобы сигнализировать об отказе обработчика завершения
  • контейнером, чтобы сигнализировать ошибку ввода-вывода в потоке, отличном от контейнера, при асинхронной обработке сервлетов 3.0.

Когда эта ошибка возникает, и сообщение INFO отображается в TOMCAT?

Это моментальный снимок кода, в котором появляется информационное сообщение.

  /**
     * Update the current error state to the new error state if the new error
     * state is more severe than the current error state.
     * @param errorState The error status details
     * @param t The error which occurred
     */
    protected void setErrorState(ErrorState errorState, Throwable t) {
        boolean blockIo = this.errorState.isIoAllowed() && !errorState.isIoAllowed();
        this.errorState = this.errorState.getMostSevere(errorState);
        if (blockIo && !ContainerThreadMarker.isContainerThread() && isAsync()) {
            // The error occurred on a non-container thread during async
            // processing which means not all of the necessary clean-up will
            // have been completed. Dispatch to a container thread to do the
            // clean-up. Need to do it this way to ensure that all the necessary
            // clean-up is performed.
            if (response.getStatus() < 400) {
                response.setStatus(500);
            }
            getLog().info(sm.getString("abstractProcessor.nonContainerThreadError"), t);  // This section gives the INFO message "INFO: An error occurred in processing while on a non-container thread. The connection will be closed immediately"
            socketWrapper.processSocket(SocketEvent.ERROR, true);
        }
    }

Как может произойти DEADLOCK?

Когда запрос использует последовательность из нескольких start(); dispatch() с неконтейнерными потоками возможно, чтобы предыдущий dispatch() вмешивался в следующий start(). Этот замок предотвращает это. Это выделенный объект, так как пользовательский код может блокировать AsyncContext, поэтому, если код контейнера также блокирует этот объект, могут возникнуть взаимоблокировки.

Как неконтейнерный поток определяет текущее состояние ошибки и дает ответ?

С введением асинхронной обработки и возможности non-container threads calling sendError() tracking the current error state и обеспечения того, чтобы страница с правильной ошибкой стала более сложной. Этот атрибут состояния помогает отслеживать текущее состояние ошибки и информировать вызывающих абонентов, которые пытаются изменить состояние, если изменение было успешным или если другой поток был первым.

   /** 
     * The state machine is very simple:
     *
     * 0 - NONE
     * 1 - NOT_REPORTED
     * 2 - REPORTED
     *
     *
     *   -->---->-- >NONE
     *   |   |        |
     *   |   |        | setError()
     *   ^   ^        |
     *   |   |       \|/
     *   |   |-<-NOT_REPORTED
     *   |            |
     *   ^            | report()
     *   |            |
     *   |           \|/
     *   |----<----REPORTED
     * 
     */

Когда метод executeNonBlockingDispatches (...) вызывается в неконтейнерном потоке и как он взаимодействует с SocketWrapper?

Этот метод вызывается, когда неблокирующий IO инициируется путем определения прослушивателя чтения и/или записи в потоке, отличном от контейнера. Он вызывается, как только поток, не содержащий контейнера, завершается так, что первые вызовы onWritePossible() и/или onDataAvailable() по мере необходимости создаются контейнером.

Для обработки рассылок требуется (for APR/native at least), чтобы сокет был добавлен в очередь ожиданияRequests. Это может не произойти к тому моменту, когда завершится неконтейнерный поток, инициирующий вызов этого метода. Следовательно, закодированные синхронизации на SocketWrapper в качестве потока контейнера, который инициировал этот неконтейнерный поток, удерживает блокировку на SocketWrapper. Контейнерный поток добавит сокет в очередь ожиданияRequests, прежде чем освободить блокировку на socketWrapper. Поэтому, получив блокировку на socketWrapper перед обработкой отправлений, мы можем быть уверены, что сокет был добавлен в waitingRequests queue.