Równoległe odpalenie rest templatów

0

Zastanawiam się, jakie są obecnie najlepsze sposoby na odpalenie kilku zapytań http (używam rest templatki) równolegle ? Załóżmy, że muszę pobrać dane z kilku różnych serwisów. Wiem, że request w springu tworzy osobny wątek i są jakieś problemy z tym, że wyjście poza niego powoduje utratę danych i jest to spowodowane działaniem ThreadLocal. Czy mogę użyć jakiś ExecutorServiców lub zrobić metody z @Async zwracające Future<T> czy jakie są teraz dobre praktyki w normalnych springu ?

0

A czy te operacje są tak długotrwałe że musze być zrównoleglone?

1

Niekoniecznie, ale dlaczego tego nie odpalić równolegle ?

0

Ja uważam że jeśli nie ma takiej potrzeby, tzn operacje są bardzo krótkie to nie warto, po prostu więcej męczenia się z synchronizacją, a raczej to że poszczególne taski się skończą. Jeżeli całość w kolejności jedno po drugim trwa bardzo krótko to ja bym to tak zostawił, nie ma sensu wyciągac armaty na muchę :)

0

Tu masz przykłady https://github.com/setblackWs/springFibb/blob/master/src/main/java/pl/setblack/fb/Example.java
Generalnie możesz nawet w klasycznym springu odpalać asynchroniczne requesty.

Albo chamsko zablokujesz jak juzprzyjdą odpowiedzi od wszystkich:

if (n < 2) {
            return 1;
        } else {
            CompletionStage<Long> fib_n_1 = requestFibb(n - 1);
            CompletionStage<Long> fib_n_2 = requestFibb(n - 2);
            try {
                return fib_n_1.thenCombine(fib_n_2, (n_1, n_2) -> n_1 + n_2).toCompletableFuture().get();
            } catch (Exception ie) {
                throw new IllegalStateException(ie);
            }
}

//....
   private CompletionStage<Long> requestFibb(long n) {
        AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
        CompletableFuture<Response> f = asyncHttpClient.prepareGet("http://localhost:8080/fibb?n=" + n).execute()
                .toCompletableFuture();
        return f.thenApply(resp -> {
            try {
                asyncHttpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return Long.parseLong(resp.getResponseBody());
        });

}

albo nawet zwrócisz Promise z serwisu

@RequestMapping("/fibba")
    public DeferredResult<Long> executeSlowTask(@RequestParam(value = "n", defaultValue = "1") long n) {

        DeferredResult<Long> deferredResult = new DeferredResult<>();
        //System.out.println("getting fibba(" + n + ") THREADS: " + java.lang.Thread.activeCount());
        if (n < 2) {
            deferredResult.setResult(1L);

        } else {
            CompletionStage<Long> fib_n_1 = requestFibba(n - 1);
            CompletionStage<Long> fib_n_2 = requestFibba(n - 2);

            fib_n_1.thenCombine(fib_n_2, (n_1, n_2) -> n_1 + n_2).thenAccept((res)->deferredResult.setResult(res));
        }
        return deferredResult;
    }

//....
 private CompletionStage<Long> requestFibba(long n) {

        CompletableFuture<Response> f = asyncHttpClient.prepareGet("http://localhost:8080/fibba?n=" + n).execute()
                .toCompletableFuture();
        return f.thenApply(resp -> {

            return Long.parseLong(resp.getResponseBody());
        });

}

(btw. to są przykłady na problemy w klasycznym springu -rekursywny http. kod nie jest sensowny, ani optymalny, ale ogarniesz co trzeba.

W nowym spring WebFlux jest o klasę ładniej. Ale tam to nawet nie mam request per thread, nie ma beanów itp. więc to inna bajka.

0

@jarekr000000: A czy gdyby problem był taki że jest bardzo dużo użytkowników naraz i apka zamula, to możnaby się pokusić o bardziej hardwerowe rozwiązanie - więcej serwerów i load balancer?

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