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

У меня есть служба REST, реализованная с помощью JAX-RS. Некоторые операции занимают много времени, возможно, 15–30 минут. В таких случаях я предпочитаю направить фоновый поток для обработки длительной операции, а затем немедленно ответить HTTP-статусом 202 ПРИНЯТО. Ответ будет содержать заголовок местоположения с URL-адресом, который клиенты могут использовать для опроса о ходе выполнения.

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

У меня следующие вопросы:

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

Кроме того, чтобы не управлять собственными потоками, я изучил API асинхронного сервера JAX-RS. К сожалению, хотя это увеличивает пропускную способность сервера, это не позволяет мне сразу же ответить «ПРИНЯТО».

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

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.

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


person cmd    schedule 13.09.2013    source источник


Ответы (3)


Я думаю, что 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();
person Wojtek Owczarczyk    schedule 05.03.2014
comment
Возврат 202 не дойдет до клиента. Я действительно пробовал! - person Vishnu G S; 02.11.2016
comment
Не работает. Не должно быть принятого ответа. Ответ Сотириоса Делиманолиса верен. - person ccleve; 19.05.2017
comment
Согласен - это не ответ на вопрос. Запрашивающая сторона хотела бы получить код для возврата 202 из его метода. - person cs94njw; 11.04.2018

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

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

person Sotirios Delimanolis    schedule 13.09.2013
comment
Спасибо. Я согласен с тем, что для управления потоками следует использовать что-то благословенное, например ExecutorService. Я все еще испытываю тошноту по поводу отправки их. Кроме того, я использую EJB, и спецификация EJB гласит: • Корпоративный компонент не должен пытаться управлять потоками. Корпоративный компонент не должен пытаться запустить, остановить, приостановить или возобновить поток, а также изменить приоритет или имя потока. Корпоративный компонент не должен пытаться управлять группами потоков. Могут ли мои runnables быть сессионными компонентами с отслеживанием состояния? Возможно да? Может ли класс, который использует ExecutorService для отправки потока, быть синглтоном без сохранения состояния? Нет? - person cmd; 13.09.2013
comment
@cmd С EJB, возможно, посмотрите это - person Sotirios Delimanolis; 13.09.2013
comment
Спасибо, это очень близко к тому, за что я собираюсь. - person cmd; 14.09.2013
comment
@SotiriosDelimanolis Пожалуйста, посмотрите это и помогите. Спасибо за ваше время. stackoverflow.com/ questions / 19706788 / - person Kumar; 06.11.2013

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

person Justinas Jakavonis    schedule 06.05.2016