Обработка неожиданного завершения запросов в сервлетах - PullRequest
2 голосов
/ 09 июня 2010

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

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

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

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

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

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

Raphael

1 Ответ

2 голосов
/ 09 июня 2010

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

Обычно закрытие соединения с БД (и других ресурсов) должно происходить в блоке 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) {}
}
...