REST с JAX-RS - обработка длительных операций

У меня есть служба REST, реализованная с JAX-RS. Некоторым операциям требуется много времени, возможно, 15-30 минут. Для этих случаев моя склонность - отправить фоновый поток для обработки длительной операции, а затем немедленно ответить на HTTP-статус 202 ACCEPTED. Ответ будет содержать заголовок местоположения с URL-адресом, который клиенты могут использовать для опроса для прогресса.

Этот подход требует создания потоков для обработки длительных операций, так что 202 ACCEPTED может быть немедленно возвращен. Я также знаю, что создание собственных потоков в контейнере Java EE, как правило, является плохой практикой!

Мои вопросы таковы:

  • Согласны ли люди, что это правильный подход?
  • Предполагая, что это правильно, могут ли люди рекомендовать решение "хорошей практики", которое позволяет мне отправить длинную операцию в фоновом режиме и немедленно вернуться?

Кроме того, чтобы избежать управления моими потоками, я заглянул в асинхронный сервер Apache JAX-RS. К сожалению, хотя это повышает пропускную способность сервера, он не позволит мне немедленно ответить ACCEPTED.

Джерси заявляет следующее:

Note that the use of server-side asynchronous processing model will not improve the 
request processing time perceived by the client. It will however increase the
throughput of the server, by releasing the initial request processing thread back to
the I/O container while the request may still be waiting in a queue for processing or    
the processing may still be running on another dedicated thread. The released I/O  
container thread can be used to accept and process new incoming request connections.

Любая помощь приветствуется. Спасибо!

Ответ 1

Я думаю, что Jersey Async docs исчерпывает тему довольно хорошо. Вот краткий фрагмент:

@Path("/async/longRunning")
public class MyResource {

   @GET
   public void longRunningOp(@Suspended final AsyncResponse ar) {
       executor.submit(
            new Runnable() {
                public void run() {
                    executeLongRunningOp();
                    ar.resume("Hello async world!");
                } });
  }
}

Когда дело доходит до следующей цитаты из документов:

Обратите внимание, что использование модели асинхронной обработки на стороне сервера будет не улучшать время обработки запроса, воспринимаемое клиентом. (...)

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

return Response.status(Status.ACCEPTED).build();

Ответ 2

Я также знаю, что создание ваших собственных потоков в контейнере Java EE, как правило, является плохой практикой!

Хотя в большинстве случаев это верно, в этом случае у вас нет выбора. По крайней мере, не создавайте свои экземпляры Thread самостоятельно. Пусть a ExecutorService сделает это за вас. Если что-нибудь, сделайте, чтобы этот ExecutorService имел достаточно большой пул и делился им со всеми вашими компонентами.

Ответ 3

Я бы сделал метод, который немедленно возвращает ответ с идентификатором процесса и временем, когда он будет завершен. Расчет начинается в фоновом режиме и кэшируется в течение некоторого времени после завершения. Затем клиент пытается получить информацию с определенным идентификатором и получает связанный ответ.