Jak zrealizować takie asynchorniczne zapytania?

0

Mam klienta webowego do aplikacji REST napisanej w Spring Boot. Po nadejściu zapytania POST uruchamiane jest zapytanie do bazy danych, które może trwać minutę, 10 minut albo znacznie dłużej. Dlatego będzie to realizowane na serwerze asynchronicznie. Teraz mam taki pomysł, żeby po powiedzmy maksymalnie 3 minutach wykonywania zapytania serwlet zwrócił odpowiedź do klienta. Normalnie byłby to timeout i info, że zapytanie trwa zbyt długo. Ale ja chcę to zrobić tak, że zapytanie nadal się realizuje, a po zakończeniu wynik jest przesyłany na maila. Klient dostaje info, że taka zmiana nastąpiła. Jeżeli zapytanie trwa mniej niż 3 minuty, to klient dostaje wynik zapytania.
Po stroni interfejsu webowego nie widzę tutaj problemu, bo wywołuję zapytanie tak czy inaczej asynchronicznie i dalsza część realizuje się po odpowiedzi serwera nie blokując interfejsu użytkownika. Będzie tylko ograniczenie ile takich zapytań można ustawić w kolejce. Tak więc pytanie dotyczy jak to można zrobić po stronie serwera.
Drugi problem to taki, czy można jakoś pobrać ilość wątków realizujących asynchroniczne zapytania w spring boot? Nie chciałbym, żeby ktoś naklikał kolejkę w kliencie przekraczającą możliwości serwera.

Z góry dziękuję za pomysły w temacie.

0

Chodzi Ci o to jak asynchronicznie procesować dane przez serwer? Bo nie zrozumiałem chyba do końca pytania :P

2

Na Spring5 (masz to w Spring boot 2.0) robię to przez zwracanie Flux<MyProgessInfos> i całkiem działa.

To zwraca json stream, które w po stronie clienta odbieram przy pomocy czegoś co się nazywa oboe.js (wbrew pozorom to własnie zaimplementowanie klienta było problemem),

Serwer do strumienia okresowo wrzuca postęp prac (progress bar), a na koniec rezultat.

*Spring 5, flux, projectreactor, oboe, json streaming. *

Jak chcesz ograniczyć iloś równoczesnie przetwarzanych zapytań - to możesz je przepuszczać przez task executory z ustawionym pool-size:
https://docs.spring.io/autorepo/docs/spring-framework/3.2.x/spring-framework-reference/html/scheduling.html

Ale z tego normalnie nie korzystam, bo nie korzystam ze Springa (Spring 5 Web Flux to nie Spring, u mnie działają normalne executory.)

0

Jeszcze może doprecyzuję o co mi chodzi, a o co mi nie chodzi:

  1. Zapuszczam w spring boot asynchronicznie proces, który długo trwa. Po wykonaniu zapisze on plik na dysku.
  2. Jeżeli proces zakończy się w ciągu 3 minut, to klient dostanie odpowiedź zawierającą URL do tego pliku.
  3. Jeżeli przetwarzanie trwa dłużej, to po 3 minutach klient dostaje odpowiedź, że adres do pliku zostanie do niego wysłany mailem.
  4. Po zakończeniu procesu zapisywany jest plik i wysyłany email na podany adres zawierający URL wygenerowanego pliku.

Chodzi o to, żeby interfejs webowy zawsze dostawał odpowiedź w ciągu 3 minut. Podczas uruchomienia zadania nie można określić ile czasu będzie się ono realizować, stąd też potrzebna jest akcja inicjowana poprzez przekroczenie czasu wykonania.

Z TaskExecutor jeszcze badam sprawę, ale wychodzi mi, że on może ograniczyć liczbę uruchomionych jednocześnie wątków, a pozostałe skolejkować. Natomiast ja bym chciał, żeby klient dostał wiadomość, że nie może wykonać zadania, bo jest kolejka i żeby spróbował później. W przeciwnym razie klient puści zadanie, zostanie ustawione w kolejce na setnej pozycji. Klient zobaczy, że nie dostał maila, więc jeszcze raz uruchomi zadanie. I tak w kółko. Człowieka nie zmienię, więc chcę program tak zmienić, żeby był na to odporny.

1

No to żaden Flux nie jest Ci potrzebny.
W Springu mozesz to zrobić tak:

  1. Zrób sobie tego executora ( kóry np. dziala na X watkach )
  2. Wrzucaj zadania do tego executora- przez **submit **- bedziesz dostawał objekt typu Future
  3. Robisz future.get(3, TimeUnit.MINUTES)
  4. zwracasz klientowi wynik z get, ewentualnie wynik "sorry" jesli poleci TimeoutException

Gdyby się pojawiło takie pytanie: ja nie piszę, że tak należy programować, ale to Spring Boot i to chyba najprostsze rozwiązanie jak już się w Spring bagnie siedzi.

0

Wygląda na to, że ta metoda get z podaniem timeout będzie rozwiązaniem problemu. Ale jeszcze pytanie z innej beczki:
dla czego "to chyba najprostsze rozwiązanie jak już się w Spring bagnie siedzi"? Czy spring boot jest już niemodny, pase i w ogóle? To co teraz się powinno używać, żeby być trendy?

1 użytkowników online, w tym zalogowanych: 0, gości: 1