powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / странное поведение AsyncContext
45 сообщений из 45, показаны все 2 страниц
странное поведение AsyncContext
    #39029712
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
jetty 9
spring 4

есть такой контроллер :

когда


context.setTimeout(3000);
время выставлено больше чем суммарное время работы в треде все ок!
клиент видит 10 записей .


стоит выставить его меньше

и начинается :

в страницу попадает непонятно сколько записей ....а в логе на сервере

Код: java
1.
2.
3.
4.
5.
    try {
                    context.complete();
                } catch (Exception e) {
                    System.out.println(e);
                }



ловится

Код: java
1.
2.
3.
4.
5.
6.
java.lang.IllegalStateException: AsyncContext completed
java.lang.IllegalStateException: AsyncContext completed
java.lang.IllegalStateException: AsyncContext completed
java.lang.IllegalStateException: AsyncContext completed
java.lang.IllegalStateException: AsyncContext completed
java.lang.IllegalStateException: AsyncContext completed



вместо одного ...


если убрать


Код: java
1.
2.
3.
4.
5.
//try {
                    context.complete();
                //} catch (Exception e) {
                //    System.out.println(e);
               // }



то

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
Exception in thread "Thread-44" java.lang.IllegalStateException: AsyncContext completed
	at org.eclipse.jetty.server.AsyncContextState.state(AsyncContextState.java:47)
	at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:92)
	at ru.stoloto.wave.s3.controllers.RestController.lambda$hellos$2(RestController.java:106)
	at ru.stoloto.wave.s3.controllers.RestController$$Lambda$17/412150306.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-46" java.lang.IllegalStateException: AsyncContext completed
	at org.eclipse.jetty.server.AsyncContextState.state(AsyncContextState.java:47)
	at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:92)
	at ru.stoloto.wave.s3.controllers.RestController.lambda$hellos$2(RestController.java:106)
	at ru.stoloto.wave.s3.controllers.RestController$$Lambda$17/412150306.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-41" java.lang.IllegalStateException: AsyncContext completed
	at org.eclipse.jetty.server.AsyncContextState.state(AsyncContextState.java:47)
	at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:92)
	at ru.stoloto.wave.s3.controllers.RestController.lambda$hellos$2(RestController.java:106)
	at ru.stoloto.wave.s3.controllers.RestController$$Lambda$17/412150306.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-43" java.lang.IllegalStateException: AsyncContext completed
	at org.eclipse.jetty.server.AsyncContextState.state(AsyncContextState.java:47)
	at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:92)
	at ru.stoloto.wave.s3.controllers.RestController.lambda$hellos$2(RestController.java:106)
	at ru.stoloto.wave.s3.controllers.RestController$$Lambda$17/412150306.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-45" java.lang.IllegalStateException: AsyncContext completed
	at org.eclipse.jetty.server.AsyncContextState.state(AsyncContextState.java:47)
	at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:92)
	at ru.stoloto.wave.s3.controllers.RestController.lambda$hellos$2(RestController.java:106)
	at ru.stoloto.wave.s3.controllers.RestController$$Lambda$17/412150306.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-42" java.lang.IllegalStateException: AsyncContext completed
	at org.eclipse.jetty.server.AsyncContextState.state(AsyncContextState.java:47)
	at org.eclipse.jetty.server.AsyncContextState.complete(AsyncContextState.java:92)
	at ru.stoloto.wave.s3.controllers.RestController.lambda$hellos$2(RestController.java:106)
	at ru.stoloto.wave.s3.controllers.RestController$$Lambda$17/412150306.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)




а бывает что и всякие интересные ошибки самого спринга

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
 @RequestMapping("/hellos")
    public void hellos(HttpServletRequest request, HttpServletResponse response) {

     final AsyncContext context = request.startAsync();
        context.setTimeout(3000);
        
        Thread t = new Thread(() -> {
            
            try {
               ServletResponse res = context.getResponse(); 
               res.setContentType("text/palin");
               
                PrintWriter out = res.getWriter();
                for (int i = 0; i < 10; i++) {
                   out.printf(" random : %s\n", Math.random());
                   out.flush();
                   Thread.sleep(2000);
                }
                
                out.flush();
               
            } catch (Exception e) {
            }finally{
                
                try {
                    context.complete();
                } catch (Exception e) {
                    System.out.println(e);
                }
                
            }
          
            
            
        });
        
        t.start();
    }
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39029732
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Во-первых асинхронная обработка в Servlet API появилась для того, чтобы не работать с потокам там, где может быть череповато.
Поэтому непонятно, что делает new Thread() в вашем коде.

Во-вторых, асинхронная обработка должна быть или диспетчеризирована запрос или явно завершена .

В-третьих, HTTP предусматривает три значения тайм-аутов:
1. До получения строки запроса - секунды;
2. До получения всего заголовка - (две-три) минуты;
3. При чтении тела запроса или записи ответа - десять-пятнадцать минут.
С какого перепугу выставлены отбалдянские три секунды - совершенно непонятно.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39029738
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovВо-первых асинхронная обработка в Servlet API появилась для того, чтобы не работать с потокам там, где может быть череповато.
Поэтому непонятно, что делает new Thread() в вашем коде.

Во-вторых, асинхронная обработка должна быть или диспетчеризирована запрос или явно завершена .

В-третьих, HTTP предусматривает три значения тайм-аутов:
1. До получения строки запроса - секунды;
2. До получения всего заголовка - (две-три) минуты;
3. При чтении тела запроса или записи ответа - десять-пятнадцать минут.
С какого перепугу выставлены отбалдянские три секунды - совершенно непонятно.


Аммм... ну давайте Thread вынесу в отдельный класс ... в нем еще создам очередь в которую буду класть AsyncContext/


AsyncListener - добавил для наглядности ...

вывод такой :

AsyncListener

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
   @RequestMapping("/hellos")
    public void hellos(HttpServletRequest request, HttpServletResponse response) {

        final AsyncContext context = request.startAsync();
//        context.setTimeout(3000);
        
           context.addListener(new AsyncListener() {

            @Override
            public void onComplete(AsyncEvent event) throws IOException {
                System.out.println("onComplete");
            }

            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                System.out.println("onTimeout");
                ServletResponse response = event.getAsyncContext().getResponse();
                PrintWriter out = response.getWriter();
                out.write("onTimeout \n");
                out.flush();
            }

            @Override
            public void onError(AsyncEvent event) throws IOException {
                  System.out.println("onError");
            }

            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {
                System.out.println("onStartAsync");
            }
        });
        
        

        Thread t = new Thread(() -> {

            try {
                ServletResponse res = context.getResponse();
                res.setContentType("text/plain");

                PrintWriter out = res.getWriter();
                for (int i = 0; i < 10; i++) {
                    out.write( i +" "+  Thread.currentThread().getName() + String.format(" random : %s\n", Math.random() ));
                    out.flush();
                    Thread.sleep(1000);
                }

                out.write("Done\n");
                out.flush();

            } catch (Exception e) {
            } finally {

                //try {
                    context.complete();
                //} catch (Exception e) {
                //    System.out.println(e);
               // }

            }

        });
        t.setName("myThread");

        t.start();
    }
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39029748
0FD
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39029753
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
0FD,

у меня сложилось впечатление - что гугл хром посылает повторные запросы .... может быть в это же соединение ... поставил бряку обновил страницу в браузере и ловлю несколько точек ...
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39029756
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У вас кардинальное непонимание что такое асинхронность в сервлетах.

Начнём по порядку.
Асинхронная обработка требуется не "шоп було", а при наличии веских причин. Основных - две.
1. Мы можем и должны обрабатывать данные в процессе чтения тела запроса.
Разумеется, это можно сделать и без асинхронности, но, скорее всего, получится неудобоваримое спагетти. А при асинхронной обработке у нас будет два чётко специализированных метода и какой-то механизм синхронизации их работы.
2. Есть много относительно медленных клиентов и вам "кровь из носу" требуется сэкономить ресурсы контейнера.
Реализуем слушатели "по готовности" и контейнер получает возможность "отбирать" рабочий поток исполнения пока метод ждёт данные. Как и насколько это реализуется на практике - не знаю.

Так ни в одном из сценариев (включая любые другие) не имеете права создавать потоки самостоятельно - вы обязаны создать класс, реализующий j.l.Runnable (привет, интерфейсы) и предоставить этот класс методу start асинхронного контекста.
Контейнер создаст (возьмёт из пула) рабочий поток и передаст ему ваш метод run.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39029759
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
java.lang.ClassCastException: org.springframework.web.context.request.async.WebAsyncManager cannot be cast to org.springframework.web.context.request.async.WebAsyncManager
	at org.springframework.web.context.request.async.WebAsyncUtils.getAsyncManager(WebAsyncUtils.java:46)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:960)
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:816)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:583)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:566)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1114)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1048)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:187)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:119)
	at org.eclipse.jetty.server.Server.handleAsync(Server.java:567)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:339)
	at org.eclipse.jetty.server.HttpChannel.run(HttpChannel.java:261)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
	at java.lang.Thread.run(Thread.java:745)
2015-08-14 19:35:05.038:WARN:oejs.HttpChannel:qtp75480150-16: Could not send response error 500: java.lang.ClassCastException: org.springframework.web.context.request.async.WebAsyncManager cannot be cast to org.springframework.web.context.request.async.WebAsyncManager
onError
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39029762
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovУ вас кардинальное непонимание что такое асинхронность в сервлетах.

Начнём по порядку.
Асинхронная обработка требуется не "шоп було", а при наличии веских причин. Основных - две.
1. Мы можем и должны обрабатывать данные в процессе чтения тела запроса.
Разумеется, это можно сделать и без асинхронности, но, скорее всего, получится неудобоваримое спагетти. А при асинхронной обработке у нас будет два чётко специализированных метода и какой-то механизм синхронизации их работы.
2. Есть много относительно медленных клиентов и вам "кровь из носу" требуется сэкономить ресурсы контейнера.
Реализуем слушатели "по готовности" и контейнер получает возможность "отбирать" рабочий поток исполнения пока метод ждёт данные. Как и насколько это реализуется на практике - не знаю.

Так ни в одном из сценариев (включая любые другие) не имеете права создавать потоки самостоятельно - вы обязаны создать класс, реализующий j.l.Runnable (привет, интерфейсы) и предоставить этот класс методу start асинхронного контекста.
Контейнер создаст (возьмёт из пула) рабочий поток и передаст ему ваш метод run.

грубо говоря - что хочу - есть очень долгая операция - отчет , выборка ... итд ..
клиент дернул ссылку - хочу отчет ... запрос прилетел - под него создался отдельный поток , поток сервлета освободился ... клиенты посылаются уведомления фоном что все ок делается ... потом когда он сгенеировался - ему его показали ...
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39029770
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum1грубо говоря - что хочу - есть очень долгая операция - отчет , выборка ... итд ..
клиент дернул ссылку - хочу отчет ... запрос прилетел - под него создался отдельный поток , поток сервлета освободился ... клиенты посылаются уведомления фоном что все ок делается ... потом когда он сгенеировался - ему его показали ...Это всё не так делается.
Если клиент не хочет ждать дольше некоторого времени, то вы должны принять данные, поставить статус перенаправления, указав ссылку, по которой должен быть взят результат (опционно - время через которое надо проверить готовность) и зафиксировать ответ.
Запросы отправляются на обработку, результаты которой помещаются в, например, хэш-таблицу. Естественно, каждому запросу и каждой ссылке ставится по которому будем искать и сопоставлять.
Если клиент пришёл за результатом, который ещё не готов - немного ждём и, если, всё-таки, не готово опять ставим статус перенаправления. Ждём достаточно долго, чтобы не получалось слишком много перенаправлений, но не так долго, чтобы срабатывали тайм-ауты HTTP-протокола.
Асинхронность, как таковая, здесь не нужна.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39029908
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovВо-первых асинхронная обработка в Servlet API появилась для того, чтобы не работать с потокам там, где может быть череповато.
Поэтому непонятно, что делает new Thread() в вашем коде.

Во-вторых, асинхронная обработка должна быть или диспетчеризирована запрос или явно завершена .

В-третьих, HTTP предусматривает три значения тайм-аутов:
1. До получения строки запроса - секунды;
2. До получения всего заголовка - (две-три) минуты;
3. При чтении тела запроса или записи ответа - десять-пятнадцать минут.
С какого перепугу выставлены отбалдянские три секунды - совершенно непонятно.


Поэтому непонятно, что делает new Thread() в вашем коде.

Ну в таком упрошенном примере это можно понимать как:

замыкание , у вас есть рул потоков в сервлете и каждый пользователь берет из этого пула по потоку вызывая при этом генерацию отчета - долгая операция ... по умолчанию в jetty из 200
<Set name="maxThreads">200</Set>

т.е если придет 201 пользователь , он либо попалдает в очередь ArrayBlockingQueue (6000) либо получает 500.

создавая внутри потока сервлета новый тред - мы тем самым освобождаем тред сервлета.

тут конечно вопрос : когда работа в новом треде будет закончена , через что этот контектст возвращает результат и как он это делает ? через себя или через пул сервлета ???


Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Set name="ThreadPool">
      <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
        <!-- specify a bounded queue -->
        <Arg>
           <New class="java.util.concurrent.ArrayBlockingQueue">
              <Arg type="int">6000</Arg>
           </New>
      </Arg>
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">200</Set>
        <Set name="detailedDump">false</Set>
      </New>
    </Set>
</Configure>




Во-вторых, асинхронная обработка должна быть или запрос или явно завершена

context.complete();

1. До получения строки запроса - секунды;
2. До получения всего заголовка - (две-три) минуты;
3. При чтении тела запроса или записи ответа - десять-пятнадцать минут.
С какого перепугу выставлены отбалдянские три секунды - совершенно непонятно


просто не хочу ждать по несколько минут ... чтобы проверить работоспособность искусственно занизил время

логика приложения должна быть такая : к примеру если клиент не получил ответ в течении 3 секунд - он на стороне js = должен оборвать соединение , тоже самое должен сдлеать и сервер - если он е успел за 3 секунда обработать запрос- он должен прекратить его выполнение выполнить context.complete(); и вернуть 500 ... итд

возможно код сильно странно выглядит , но для того чтобы разобраться без всяких эффектов самое то :

могу переписать в таком виде : где будет очередь BlockingQueue
и один тред трудяга - который эту очередь будет разбирать ...

или можно заменить его на

private final static ExecutorService executorService = Executors.newFixedThreadPool(2);



Было :

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
@WebServlet(urlPatterns = "/BlockingServlet")
public class BlockingServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  protected void doGet(HttpServletRequest request,
                       HttpServletResponse response) throws ServletException, IOException {
    try {
      long start = System.currentTimeMillis();
      Thread.sleep(new Random().nextInt(2000));
      String name = Thread.currentThread().getName();
      long duration = System.currentTimeMillis() - start;
      response.getWriter().printf("Thread %s completed the task in %d ms.", name, duration);
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage(), e);
    }
  }



стало

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
@WebServlet(asyncSupported = true, value = "/AsyncServlet")
public class AsyncServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Work.add(request.startAsync());
  }
}



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
public class Work implements ServletContextListener {
  private static final BlockingQueue queue = new LinkedBlockingQueue();

  private volatile Thread thread;

  public static void add(AsyncContext c) {
    queue.add(c);
  }

  @Override
  public void contextInitialized(ServletContextEvent servletContextEvent) {
    thread = new Thread(new Runnable() {
      @Override
      public void run() {
        while (true) {
          try {
            Thread.sleep(2000);
            AsyncContext context;
            while ((context = queue.poll()) != null) {
              try {
                ServletResponse response = context.getResponse();
                response.setContentType("text/plain");
                PrintWriter out = response.getWriter();
                out.printf("Thread %s completed the task", Thread.currentThread().getName());
                out.flush();
              } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
              } finally {
                context.complete();
              }
            }
          } catch (InterruptedException e) {
            return;
          }
        }
      }
    });
    thread.start();
  }

  @Override
  public void contextDestroyed(ServletContextEvent servletContextEvent) {
    thread.interrupt();
  }
}





Смысл асинхронности :

в системе с одной стороны на предприятии сидит более 200 человек и они шлют запросы на генерацию отчетов - к cерверу jetty

jetty - выступает клиентов (внутри создается http post запрос к серверу отчетов) ... выяснилось - что сервер отчетов не может работать в многопоточном режиме :(

что делать ?

можно было бы обойтись без асинхронности :

как было раньше

так же ставить все запросы в очередь , а обрабатывать их в один поток ...

а с клиента делать пулинг - готов отчето или нет ... такой ddos jetty /

мне показалось что лучше уж пусть клиент повисит немного в очереди и посмотрит процесс выполнения запроса ... чем будет слать запросы


как было сделано :
на клиента стоит скрипт и по кнопке идут запросы к url дай отчет в цикле ...

сервер возвращает либо жди ...либо готово ...

Код: java
1.
2.
3.
4.
5.
6.
7.
       @RequestMapping(value="/user/report")
	@Transactional(readOnly = false)
	public void report(HttpServletRequest request, HttpServletResponse response) throws IOException {
		User user = userService.getCurrent();
		ReportResult result = reportHolder.report(user);
		response.getWriter().print(result.toString());
	}



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
private static final long UPDATE_INTERVAL = 5 * 1000;

	private final ConcurrentHashMap<Long, ReportResult>reportCache = new ConcurrentHashMap<Long, ReportResult>();

	public ReportResult report(final User user) {
				dropExpired();
		if (reportCache.containsKey(user.getId()))
			return reportCache.get(user.getId());
                
            		ReportResult pending = ReportResult.pending(Long.parseLong(user.getLogin()));
		ReportResult actualReportResult = reportCache.putIfAbsent(user.getId(), pending);
		if (actualReportResult == null) {
			executorService.submit(new Callable<ReportResult>() {
				public AccountResult call() throws Exception {
					ReportResult report = service.getUserReport(user);
					reportCache.put(user.getId(), report);
					
					return report;
				}
			});
		}

		if (actualReportResult == null) {
			actualReportResult = pending;
		}
		return actualReportResult;
	}



как так ... где ReportResult report = service.getUserReport(user); получение отчета .



0FDAtum1

https://docs.oracle.com/javaee/6/api/javax/servlet/AsyncContext.html#start(java.lang.Runnable)

Код: java
1.
 context.start(() -> {...});



если просто пихать туда созданный тред
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
@RequestMapping("/hellot")
    public void hellot(HttpServletRequest request, HttpServletResponse response) {

        final AsyncContext context = request.startAsync();
        context.setTimeout(3000);

        context.start(() -> {

            try {
                ServletResponse res = context.getResponse();
                res.setContentType("text/plain");

                PrintWriter out = res.getWriter();
                for (int i = 0; i < 10; i++) {
                    out.write(i + " " + Thread.currentThread().getName() + String.format(" random : %s\n", Math.random()));
                    out.flush();
                    Thread.sleep(1000);
                }

                out.write("Done\n");
                out.flush();

            } catch (Exception e) {
            } finally {

                //try {
                context.complete();
                //} catch (Exception e) {
                //    System.out.println(e);
                // }

            }

        });
    }



то будет тот же эффект - при явно меньшем таймауте чем сам процесс работы ... только имена тредов будут другие из какого то пула
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030044
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для спринга - асинхронность можно разрулить средствами самого спринга :


тут только вопрос

правильно ли я понимаю что : deferredResult - нужно засунуть в findPage и там внутри вызвать

deferredResult.setResult(result.get()); ???

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
// http://spring.io/guides/gs/async-method/

@Service("lookupService")
public class LookupServiceImpl implements LookupService {

    @Async
    @Override
    public Future<String> findPage() throws InterruptedException {

        Thread.sleep(500);
        double r = Math.random();
        System.out.println("findPage" + r);
        if (r > 0.5) {
            throw new NullPointerException("test");
        }

        return new AsyncResult<>(String.valueOf(Math.random()));
    }

}



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
@ControllerAdvice
public class ExceptionHandlerController {
    
       
    @ExceptionHandler({InterruptedException.class,
        ExecutionException.class
    })
    ResponseEntity<String> handelConflicts(Exception e) {
        System.out.println("handelConflicts ");
        return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
    
    @ExceptionHandler(Exception.class)
    ResponseEntity<String> handelException(Exception e) {
        return new ResponseEntity<>(e.toString(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
@Controller
public class RestController {


      @Autowired
     LookupService lookupService;

    @RequestMapping("/hello")
    @ResponseBody
    public DeferredResult<String> hello() throws InterruptedException, ExecutionException {
        DeferredResult<String> deferredResult = new DeferredResult<>();

        Future<String> result = lookupService.findPage();
        deferredResult.setResult(result.get());

        return deferredResult;

    }






Но я в дебаге не вижу что это действительно асинхронно (не вижу что создаются треды новые) ?!

и все таки вопрос что происходит когда мы выставляем context.setTimeout(3000); время меньше чем работа самого треда открытый ???
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030047
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
получается этот вариант асинхронный?
в первом - мы будем ждать в сервлете - когда result.get() вернет значение?! так?
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
    @RequestMapping("/hellou")
    @ResponseBody
    public DeferredResult<String> hellou() throws InterruptedException, ExecutionException {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        lookupService.findPageAsync(deferredResult);
        return deferredResult;

    }



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
    @Override
    public void findPageAsync(DeferredResult<String> result) throws InterruptedException {
        Thread.sleep(500);
        double r = Math.random();
        System.out.println("findPage" + r);
        if (r > 0.5) {
            //result.setErrorResult("setErrorResult");
            throw new NullPointerException("test");
        }
        
        
     result.setResult(String.valueOf(r));
    }
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030048
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum1т.е если придет 201 пользователь , он либо попалдает в очередь ArrayBlockingQueue (6000) либо получает 500."Я худею дорогая редакция".
Т.е. увеличить размер пула до адекватного - мы не можем, а:создавая внутри потока сервлета новый тред - мы тем самым освобождаем тред сервлетаЗанять тот же самый ресурс и потерять возможность ответа клиенту - это завсегда пожалуйста.
Про грабли самостоятельного создания потоков там, где этого не надо делать - уговорили, отдельной строчки не заводим.тут конечно вопрос : когда работа в новом треде будет закончена , через что этот контектст возвращает результат и как он это делает ? через себя или через пул сервлета ??? Я ещё не говорил, что вы вообще пинцет, как не понимаете принципы работы HTTP?
Пришедший запрос обязан обработаться.
Вернёте вы клиенту ожидаемый результат, ответите "NO_CONTENT", сделаете перенаправление или вернёте ошибку - дело ваше, но "что-то" вы обязаны вернуть.логика приложения должна быть такая : к примеру если клиент не получил ответ в течении 3 секунд - он на стороне js = должен оборвать соединение , тоже самое должен сдлеать и сервер - если он е успел за 3 секунда обработать запрос- он должен прекратить его выполнение выполнить context.complete(); и вернуть 500 ... итд
возможно код сильно странно выглядит , но для того чтобы разобраться без всяких эффектов самое то :Странно это мягко сказано.
1. Не клиенту решать, сколько времени должна занимать обработка, т.к. не он её выполняет.
2. После завершения обработки контекстом сделать уже ничего нельзя. И ошибку нельзя вернуть, т.к. ошибку возвращает или SetStatus() или SendError() до завершения обработки.
3. Не хотите, чтобы клиент ждал - принимайте запрос, отправляйте на обработку и сообщайте клиенту где и когда он может посмотреть результат.Смысл асинхронности :
в системе с одной стороны на предприятии сидит более 200 человек и они шлют запросы на генерацию отчетов - к cерверу jetty
jetty - выступает клиентов (внутри создается http post запрос к серверу отчетов) ... выяснилось - что сервер отчетов не может работать в многопоточном режиме :(
что делать ?Сервер отчётов рефакторить - его, похоже, такой же "мастер" делал.
Начать можно с анализа параметров запросов: если несколько клиентов запросили априори одинаковое - напрячь сервер отчётов только одним запросом. Костыль, но позволяет не лезть в чужой код. Ну и кэширование.можно было бы обойтись без асинхронности :
как было раньше
так же ставить все запросы в очередь , а обрабатывать их в один поток ...
с клиента делать пулинг - готов отчето или нет ... такой ddos jetty /Перенаправление для того и существует, чтобы не клиенты не спрашивали у сервера того, чего он не знает.мне показалось что лучше уж пусть клиент повисит немного в очереди и посмотрит процесс выполнения запроса ... чем будет слать запросыКакое, нахрен, "посмотрит"?!
В многопоточном режиме, значит, сервер отчётов работать не умеет, а статус выполнения возвращать может???
А если не может, то "ожидательное многоточие" клиент в состоянии нарисовать без посторонней помощи.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030050
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. Sidorovсервер отчетов не может работать в многопоточном режиме :(
что делать ?
очередь заданий для него и пусть день и ночь будет загружен в одном потоке. Сваливает результат в табличку.
Если в банке 1 окошко, и электронная очередь, то все сидят синхронно в ожидании друг за другом)).
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030051
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. Sidorov
+1
это я выше аффтару
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030052
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну а для очереди заданий вообще никакие потоки не нужны. Если не тормозить клиента.
Клиент в JS может сам после заказа через пару секунд проверять статус заказа по другому адресу.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030053
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
есть вполне банальный пример сетевого принтера в винде. С его очередью, и окошком на всех сетевых клиентах.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030055
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. Sidorov , спасибо за ответы буду думать :)

Basil A. SidorovСервер отчётов рефакторить - его, похоже, такой же "мастер" делал.
Начать можно с анализа параметров запросов: если несколько клиентов запросили априори одинаковое - напрячь сервер отчётов только одним запросом. Костыль, но позволяет не лезть в чужой код. Ну и кэширование.


1. требования что отчеты должны быть онлайн .
2. кешировать нельзя .
3. одинаковых отчетов нет .
4. каждый бизнес запрос от пользователя - меняет состояние сервера - следовательно изменяться отчет .


Сразу тогда архитектурный вопрос

Это будет правильно если организовать цепочку так :
LookupService - это асинхронная работа ...
далее идет
FacadeLookupService - Это простая обертка для контроллера в котором просто идет вызов

result.get()



Код: java
1.
2.
3.
public interface LookupService {
    public Future<String> findPage() throws InterruptedException;
}



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
@Service("lookupService")
public class LookupServiceImpl implements LookupService {
    @Async
    @Override
    public Future<String> findPage() throws InterruptedException {

        Thread.sleep(500);
        double r = Math.random();
        System.out.println("findPage" + r);
        if (r > 0.5) {
            throw new NullPointerException("test");
        }
            return new AsyncResult<>(String.valueOf(Math.random()));
    }



Код: java
1.
2.
public interface FacadeLookupService {
    public void findPageAsync(DeferredResult<String> result) throws InterruptedException ,ExecutionException; 



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
@Service("facadeLookupService")
public class FacadeLookupServiceImpl implements FacadeLookupService {

    @Autowired
    LookupService lookupService;

    @Override
    public void findPageAsync(DeferredResult<String> result) throws InterruptedException, ExecutionException {
        String res = lookupService.findPage().get();
        result.setResult(res);
    }

}



и тогда контроллер :

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
@Controller
public class RestController {

    @Autowired
    FacadeLookupService facadeLookupService;

   @RequestMapping("/hellou")
    @ResponseBody
    public DeferredResult<String> hellou() throws InterruptedException, ExecutionException {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        facadeLookupService.findPageAsync(deferredResult);
        return deferredResult;

    }
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030058
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123Basil A. Sidorovпропущено...

очередь заданий для него и пусть день и ночь будет загружен в одном потоке. Сваливает результат в табличку.
Если в банке 1 окошко, и электронная очередь, то все сидят синхронно в ожидании друг за другом)).

Petro123, спасибо

я как раз привел такой пример выше ,как вариант :


но меня смущает одно но - это тред который висит постоянно и который нельзя перестартовать !

вот если бы можно было создать очередь и пул и заставить его самого из этого очереди выбирать задания ... но как?

Было :
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
@WebServlet(urlPatterns = "/BlockingServlet")
public class BlockingServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  protected void doGet(HttpServletRequest request,
                       HttpServletResponse response) throws ServletException, IOException {
    try {
      long start = System.currentTimeMillis();
      Thread.sleep(new Random().nextInt(2000));
      String name = Thread.currentThread().getName();
      long duration = System.currentTimeMillis() - start;
      response.getWriter().printf("Thread %s completed the task in %d ms.", name, duration);
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage(), e);
    }
  }


стало
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
@WebServlet(asyncSupported = true, value = "/AsyncServlet")
public class AsyncServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;

  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Work.add(request.startAsync());
  }
}


public class Work implements ServletContextListener {
  private static final BlockingQueue queue = new LinkedBlockingQueue();

  private volatile Thread thread;

  public static void add(AsyncContext c) {
    queue.add(c);
  }

  @Override
  public void contextInitialized(ServletContextEvent servletContextEvent) {
    thread = new Thread(new Runnable() {
      @Override
      public void run() {
        while (true) {
          try {
            Thread.sleep(2000);
            AsyncContext context;
            while ((context = queue.poll()) != null) {
              try {
                ServletResponse response = context.getResponse();
                response.setContentType("text/plain");
                PrintWriter out = response.getWriter();
                out.printf("Thread %s completed the task", Thread.currentThread().getName());
                out.flush();
              } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
              } finally {
                context.complete();
              }
            }
          } catch (InterruptedException e) {
            return;
          }
        }
      }
    });
    thread.start();
  }

  @Override
  public void contextDestroyed(ServletContextEvent servletContextEvent) {
    thread.interrupt();
  }
}
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030060
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum11. требования что отчеты должны быть онлайн .
от кого это требование и что под этим понимается?
Т.к. уже решение, в ТЗ так не пишут.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030061
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum14. каждый бизнес запрос от пользователя - меняет состояние сервера - следовательно изменяться отчет .
?
Если я 2 раза нажал на кнопку Отчёт после того как перекурил, то они будут разные?
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030063
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123Atum14. каждый бизнес запрос от пользователя - меняет состояние сервера - следовательно изменяться отчет .
?
Если я 2 раза нажал на кнопку Отчёт после того как перекурил, то они будут разные?

да.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030064
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum1Petro123, спасибо
я как раз привел такой пример выше ,как вариант :
не вижу.
Я предложил вариант:
- везде выкинуть Thread
- банальная запись в сервлете в БД в табличку Очередь имя отчёта и его параметры.
- вернуть клиенту сразу же номерок или токен задания.
- далее проблема клиента всё это забрать
- всё.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030065
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum1да.
я не понял почему да, но ладно. Нет проблем - вам хуже)).
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030066
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вариант А предложенный выше позволит не переписывать сервлеты и клиента при апгрейде сервера печати (узкое звено)
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030068
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123Atum1Petro123, спасибо
я как раз привел такой пример выше ,как вариант :
не вижу.
.

Work.add(request.startAsync());

...

public void run() {
while (true) {
...
а далее разгружаем очередь

while ((context = queue.poll()) != null)

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
public void contextInitialized(ServletContextEvent servletContextEvent) {
    thread = new Thread(new Runnable() {
      @Override
      public void run() {
        while (true) {
          try {
            Thread.sleep(2000);
            AsyncContext context;
            while ((context = queue.poll()) != null) {
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030069
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123- везде выкинуть Thread
если ты изучаешь потоки, тогда удачи.
Тут они не нужны. Они уже есть в контейнере, в БД, в коннекте к БД, в отчётной системе и т.д.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030070
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum1
Сразу тогда архитектурный вопрос

Это будет правильно если организовать цепочку так :
LookupService - это асинхронная работа ...
далее идет
FacadeLookupService - Это простая обертка для контроллера в котором просто идет вызов

result.get()





Код: java
1.
2.
3.
public interface LookupService {
    public Future<String> findPage() throws InterruptedException;
}



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
@Service("lookupService")
public class LookupServiceImpl implements LookupService {
    @Async
    @Override
    public Future<String> findPage() throws InterruptedException {

        Thread.sleep(500);
        double r = Math.random();
        System.out.println("findPage" + r);
        if (r > 0.5) {
            throw new NullPointerException("test");
        }
            return new AsyncResult<>(String.valueOf(Math.random()));
    }



Код: java
1.
2.
public interface FacadeLookupService {
    public void findPageAsync(DeferredResult<String> result) throws InterruptedException ,ExecutionException; 



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
@Service("facadeLookupService")
public class FacadeLookupServiceImpl implements FacadeLookupService {

    @Autowired
    LookupService lookupService;

    @Override
    public void findPageAsync(DeferredResult<String> result) throws InterruptedException, ExecutionException {
        String res = lookupService.findPage().get();
        result.setResult(res);
    }

}



и тогда контроллер :

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
@Controller
public class RestController {

    @Autowired
    FacadeLookupService facadeLookupService;

   @RequestMapping("/hellou")
    @ResponseBody
    public DeferredResult<String> hellou() throws InterruptedException, ExecutionException {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        facadeLookupService.findPageAsync(deferredResult);
        return deferredResult;

    }





Что то перемудрил c FacadeLookupService ... это все равно что просто вызвать
в контролере
Код: java
1.
2.
  Future<String> result = lookupService.findPage();
        deferredResult.setResult(result.get());



так же?

чтобы была честная асинхронность - нужно просто засунуть в метод deferredResult

так :
Код: java
1.
2.
3.
4.
public interface LookupService {
  public void findPage(DeferredResult<String> result) throws InterruptedException;
    
}



Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
@Service("lookupService")
public class LookupServiceImpl implements LookupService {

    @Async
    @Override
    public void findPage(DeferredResult<String> result) throws InterruptedException {

        Thread.sleep(500);
        double r = Math.random();
        System.out.println("findPage" + r);
        if (r > 0.5) {
            throw new NullPointerException("test");
        }

        result.setResult(String.valueOf(Math.random()));
    }



и тогда контроллер :

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
@Controller
public class RestController {

    @Autowired
    FacadeLookupService facadeLookupService;
    
    @Autowired
    LookupService lookupService;

    @RequestMapping("/hellou")
    @ResponseBody
    public DeferredResult<String> hellou() throws InterruptedException, ExecutionException {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        lookupService.findPage(deferredResult);
        return deferredResult;

    }
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030072
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123Petro123- везде выкинуть Thread
если ты изучаешь потоки, тогда удачи.
Тут они не нужны. Они уже есть в контейнере, в БД, в коннекте к БД, в отчётной системе и т.д.

Нужно больше потоков :)

ps

спасибо , так и буду делать - выкину все .
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030073
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum1спасибо , так и буду делать - выкину все .
ты не юродствуй. Вверху ТЗ.
Если оно не подошло - скажи чем.
Если у тя учебная задача - скажи честно.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030075
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum11. требования что отчеты должны быть онлайн .
2. кешировать нельзя .
3. одинаковых отчетов нет .
4. каждый бизнес запрос от пользователя - меняет состояние сервера - следовательно изменяться отчет .Пункты со второго по четвёртый понятны.
Пункт первый - иллюстрация того, как на ровном месте уронить любую систему.
Если я вас правильно понимаю, то пользователи "не хотят долго ждать". Рекомендую п(р)очитать "Мифический человеко-месяц" - там и про это есть.

Теперь о последствиях странных желаний.
Сервер отчётов принимает запрос и выполняет его столько времени, сколько он его выполняет.
Если клиент вместо того, чтобы дождаться формирования запрошенного отчёта забивает на результат и отправляет новый запрос, то через короткое время сервер отчётов будет загружен запросами, которые уже никому не требуется. Могу и дальше объяснять, но, вроде, и так всё очевидно.

Самое хреновое, что ружьё может выстрелить не только в третьем акте, но и в любой момент.
Достаточно, чтобы время формирования отчётов чуть выросло: вчера было на десятую секунды ниже порога, сегодня - на десятую секунду выше и всё - приплыли. Всё стоИт кОлом и никто ничего не понимает потому, что нигде нет никаких ошибок.

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

Если я неправ и "должны быть онлайн" это простое "нельзя кэшировать", то клиент должен ждать и ограничивает его только HTTP-таймаут на ожидание заголовка ответа. И вот если не дождался - перенаправление.
Асинхронность вам полезна, но совсем не так, как вы пытаетесь нагородить.
Если в рамках Servlet API, то делается два отдельных метода:
1. doGet/doPost, который читает запрос и может:
1.1 сделать перенаправление;
1.2 вернуть готовый результат.

2. run, в котором запрашивается отчёт и который:
1.1 или возвращает результат клиенту;
1.2 или помещает его туда, откуда его вернёт 1.2.

Для синхронизации требуется два флага:
1. "Отчёт не готов" - разрешает сделать перенаправление;
2. "Перенаправление" - запрещает методу run возвращать результат клиенту, т.к. уже делается перенаправление.
Ну и тривиальные wait/notify.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030076
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. Sidorov1.2 вернуть готовый результатразрешить вернуть готовый результат.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030077
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. SidorovBasil A. Sidorov1.2 вернуть готовый результатразрешить вернуть готовый результат
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030078
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123Atum1спасибо , так и буду делать - выкину все .
ты не юродствуй. Вверху ТЗ.
Если оно не подошло - скажи чем.
Если у тя учебная задача - скажи честно.

без юродства - все нормально . просто будет переработка исходного ТЗ и сервера отчетов ... а дальше будем думать ...

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

Другой вопрос :
по коду Да это честная асинхронность - создается SimpleAsyncTaskExecutor -3 все честно ...

но при возниковении ошибки NullPointerException - она никем не обрабатывается ... :(

клиент ничего не получает в бразуре - пустота - потом 503

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

как быть ? то ? к примеру возникла неизвестная ошибка - и как нам тогда переписать метод его сигнатуру чтобы он кем то отлавливался ???

до контроллера NullPointerException не долетел ... где то внутрях умер ...


Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
@ControllerAdvice
public class ExceptionHandlerController {
    
       
    @ExceptionHandler({InterruptedException.class,
        ExecutionException.class
    })
    ResponseEntity<String> handelConflicts(Exception e) {
        System.out.println("handelConflicts ");
        return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
    
    
    @ExceptionHandler(Exception.class)
    ResponseEntity<String> handelException(Exception e) {
        return new ResponseEntity<>(e.toString(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}






Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
чтобы была честная асинхронность - нужно просто засунуть в метод deferredResult

так : 
public interface LookupService {
  public void findPage(DeferredResult<String> result) throws InterruptedException;
    
}


@Service("lookupService")
public class LookupServiceImpl implements LookupService {

    @Async
    @Override
    public void findPage(DeferredResult<String> result) throws InterruptedException {

        Thread.sleep(500);
        double r = Math.random();
        System.out.println("findPage" + r);
        if (r > 0.5) {
            throw new NullPointerException("test");
        }

        result.setResult(String.valueOf(Math.random()));
    }


и тогда контроллер : 

@Controller
public class RestController {

    @Autowired
    FacadeLookupService facadeLookupService;
    
    @Autowired
    LookupService lookupService;

    @RequestMapping("/hellou")
    @ResponseBody
    public DeferredResult<String> hellou() throws InterruptedException, ExecutionException {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        lookupService.findPage(deferredResult);
        return deferredResult;

    } 
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030079
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. Sidorov,
+1
а ожидание флага как параметр или чем регулируем?
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030080
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123а ожидание флага как параметр или чем регулируем?Можно прочитать спеки и зашить в коде "не более двух минут".
Можно сказать "Две минуты - жестоко" и долго выбирать в диапазоне от пяти до пятнадцати секунд.
Можно сказать "Сами выбирайте" и сделать параметр в контексте, который init() вычитает, подкорректирует, если он будет менее пяти секунд или долее двух минут. При корректировке - логировать сообщение, чтобы никто потом не удивлялся.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030082
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати, насчёт "две минуты" неправ - отклик сервера ждётся дольше.
Тогда, если формирование отчётов укладывается в десять минут - вообще никакой асинхронности не требуется. Клиент отправляет запросы и ждёт ответ в фоновом режиме, чтобы "не морозить" интерфейс и сам оповещает пользователя о готовности отчёта.
Если "правильное решение" невозможно или отчёты "долго формируются" - тогда перенаправление и асинхронность, как способ упрощения кода.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030083
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. Sidorov,
+1
У фокса на AJAX вроде по умолчанию 300 сек на ответ от сервера AFAIK.
Если сделать прозрачно + логирование + статистика на видном месте (доска почёта )) ), то пользователи поймут))).
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030089
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кстати вариант который обсуждали подходит?
- Клиент по AJAX jQuery отправляет запрос с флагом асинхронно (чтобы не морозить ГУИ).
В каллбэк этого запроса на клиенте в период 300сек приходит ответ от сервлета по отчёту.
Там может стоять хоть alert('Готово'); хоть редирект на сервлет с он-лайн потоком отчёта.
Тоже никаких потоков и асинхронности не надо.
Да, если будет более 300 сек, то будет ошибка на экране "сервер занят".
Но ведь писать то ничего не надо. Это можно к вечеру внедрить и отписаться тут на форуме.
Это вроде то что сказал Basil A. Sidorov.
IMHO
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030090
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. Sidorov2. run, в котором запрашивается отчёт и который:
1 2.1 или возвращает результат клиенту;
1 2.2 или помещает его туда, откуда его вернёт 1.2.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030092
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот, то о чём говорили коротко и ясно:
https://toster.ru/q/156091
relgames @relgames Самый важный вопрос - хотите ли вы синхронный или асинхронный API?

При синхронном, пользователь отправляет запрос и ожидает ответа в этом же HTTP вызове.
Прогресс можно писать прямо в output stream сервлета, но нужно договориться о протоколе.
Например, писать строки вида STATUS REPORT: 80%, а клиент должен уметь различать такие строки от настоящих данных.

Если запрос разорвется, то должен быть механизм подключения к той же задаче. Это довольно сложно, но реально. Например, можно первым делом генерить некий ID и выдавать его в первых строках, и если соединение рвется, клиент может переподключиться с этим же ID.

При асинхронном API генерируется ID, задача ставится в очередь, а клиент получает этот ID и HTTP вызов завершается. Потом клиент должен периодически опрашивать уже другой API (например, getResult(id) ), и если результата еще нет, этот API может возвращать что-то типа "NOT READY, STATUS 85%" в хедерах.

Подходы можно комбинировать - запуск задачи может быть асинхронным, а getResult - синхронным.

Конкретная реализация зависит от многих факторов. Можно просто в Executor добавлять задачу, а статус писать в какую-нибудь очередь. Можно на JMS делать. Можно вообще другой процесс запускать и общаться с ними через std in/out.
интересен метод посылки частичного результата в запрос)).
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030103
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Человек пишет прокси.
Если проксируемый ресур не умеет сообщать "проценты выполнения", то всякие прогресс-бары должны делаться на клиенте. И десять против одного, что не умеет.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030133
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123Кстати вариант который обсуждали подходит?
- Клиент по AJAX jQuery отправляет запрос с флагом асинхронно (чтобы не морозить ГУИ).
В каллбэк этого запроса на клиенте в период 300сек приходит ответ от сервлета по отчёту.
Там может стоять хоть alert('Готово'); хоть редирект на сервлет с он-лайн потоком отчёта.
Тоже никаких потоков и асинхронности не надо.
Да, если будет более 300 сек, то будет ошибка на экране "сервер занят".
Но ведь писать то ничего не надо. Это можно к вечеру внедрить и отписаться тут на форуме.
Это вроде то что сказал Basil A. Sidorov.
IMHO

Да сейчас именно так и работает.

Но это не спасает от ddosa сервер отчетов.
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030157
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Atum1,
Т.е. 5 минут они ждут Отчёт и он не готов?
DDOS это когда вредители.
Тогда второй вариант:авторПри асинхронном API генерируется ID, задача ставится в очередь, а клиент получает этот ID и HTTP вызов завершается. Потом клиент должен периодически опрашивать уже другой API (например, getResult(id) ), и если результата еще нет, этот API может возвращать что-то типа "NOT READY, STATUS 85%" в хедерах.
Пусть заходят и берут свой отчёт хоть завтра, хоть сидя на стуле и читая сообщение "Жди..жди, я работаю".
Удачи!
...
Рейтинг: 0 / 0
странное поведение AsyncContext
    #39030564
Atum1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот , как мне показалось нормальный вариант через расписание в контроллере :

тут только выбор между fixedDelay или fixedDelay (один поток и ждет или не ждет ).
Ну и проблема с ошибкой , которая возникает внутри метода осталась ...

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
 @Controller
public class RestController {

    @Autowired
    FacadeLookupService facadeLookupService;
    
    @Autowired
    LookupService lookupService;


....

    private final Queue<DeferredResult<String>> responseBodyQueue = new ConcurrentLinkedQueue<>();

    @RequestMapping("/hellom")
    @ResponseBody
    public DeferredResult<String> hellom() throws InterruptedException, ExecutionException {
        DeferredResult<String> deferredResult = new DeferredResult<>();
        responseBodyQueue.add(deferredResult);
        return deferredResult;
    }

    @Scheduled(fixedRate = 1000) //TODO  fixedDelay =  для 1 потока
    public void processQueues() throws InterruptedException, ExecutionException {
        System.out.println("processQueues :" + responseBodyQueue.size());
        for (DeferredResult<String> deferredResult : responseBodyQueue) {
            Future<String> result = lookupService.findPage();
            deferredResult.setResult(result.get());
            responseBodyQueue.remove(deferredResult);
        }
        
    }
...
Рейтинг: 0 / 0
45 сообщений из 45, показаны все 2 страниц
Форумы / Java [игнор отключен] [закрыт для гостей] / странное поведение AsyncContext
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]