Обработка неожиданного завершения запросов в сервлетах

В настоящее время я разрабатываю веб-сервис REST с помощью Jersey / Tomcat (но приветствуется общий ответ на сервлет / контейнер). Если клиент выполняет некоторые запросы GET к службам, которые возвращают большой объем данных, из соединения MySQL.

Чтобы избежать каких-либо исключений OOM, я использую потоковый режим для MySQL.

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

Таким образом, вопрос заключается в следующем: как я могу получать уведомления, когда запрос заканчивается на моем сервере (нормально или ненормально). Могу ли я зарегистрировать какого-нибудь слушателя? Или использовать UncaughtExceptionHandler?

Я видел много вещей, связанных с обработкой исключений в Джерси, чтобы превратить их в "ответ", но ничего, чтобы справиться с преждевременным окончанием запроса. Я думаю, что Джерси или Tomcat могут просто уничтожить мою ветку без уведомления. Могу ли я поймать какое-то исключение в критических частях моих методов, чтобы знать, когда происходит такое прерывание потока?

Заранее спасибо за помощь,

Рафаэль

1 ответ

Обычно IOException будет брошен всякий раз, когда flush() или же close() был вызван на response.getOutputStream() в то время как другая сторона прервала соединение.

Обычно закрытие соединения с БД (и других ресурсов) должно происходить в finally блок из try блок, где он был открыт, так что он будет закрыт в любом случае в случае исключений.

Подводя итог, этот пример должен сделать:

String search = getItSomehow();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;

try {
    connection = database.getConnection();
    statement = connection.prepareStatement(SQL_FIND);
    statement.setString(1, search);
    resultSet = statement.executeQuery();

    if (resultSet.next()) {
        response.setContentType(resultSet.getString("contentType"));
        response.setContentLength(resultSet.getInt("contentLength")); // Optional.
        BufferedInputStream input = null;
        BufferedOutputStream output = null;
        try {
            input = new BufferedInputStream(resultSet.getBinaryStream("content"));
            output = new BufferedOutputStream(response.getOutputStream());
            byte[] buffer = new byte[1024];
            for (int length; (length = input.read(buffer)) > 0;) {
                output.write(buffer, 0, length);
                output.flush();
            }
        } finally {
            if (output != null) try { output.close(); } catch (IOException logOrIgnore) {}
            if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
        }
    } else {
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
    }
} catch (SQLException e) {
    throw new ServletException("Something failed at SQL/DB level.", e);
} finally {
    if (resultSet != null) try { resultSet.close(); } catch (SQLException logOrIgnore) {}
    if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
    if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
}
Другие вопросы по тегам