3

Sorry if this was asked before, but I didn't find a matching question.

I have an application that performs api calls to other services. I'm thinking of using WebClient over RestTemplate as it's advised by Spring. I'm performing exclusively Synchronous HTTP calls.

I know WebClient is designed with Reactive approach in mind, but in theory: Is it ok to use WebClient solely for blocking calls? I'm concerned by the fact that I have to call .block() on each call to get the data. So my questions are:

  1. How safe is it to use .block() and is it ok in general to block threads in WebClient?
  2. Is the mechanics behind blocking calls with WebClient similar to what RestTemplate does?
  3. Is there a possibility that the performance would be worse than in case I just use RestTemplate?

Thanks in advance!

Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
tracer_13
  • 33
  • 1
  • 4

4 Answers4

11

Since there seems to be misunderstandings i will try to answer the questions to the best of my knowledge.

How safe is it to use .block() and is it ok in general to block threads in WebClient?

Blocking is always safe but whether or not it affects performance is another thing. When a request comes in, it gets assigned a thread. When we do a request using RestTemplate the same thread will do the external request, and RestTemplate will block that thread under the hood in wait for the response.

This is by no means efficient usage of a thread, but its completely safe, and this is how most web servers in general have been working for the past 20 years.

When using WebClient in a non-reactive application and you block a Mono<T> (which you essentially will be doing) the framework will first check that the thread is a type of thread that you are allowed to block (not a nio-thread) and after that it uses a CountDownLatch which pauses/blocks the calling thread at CountDownLatch#await until the first onNext/onComplete/onError signal arrives. This is completely fine in a blocking application. You can find the relevant code here.

When you add WebClient to the class path you will automatically get netty as the underlying server, which could be good to know. If you wish to change that out, then you need to be explicit about it.

Also, it is recommended that if you do multiple requests, then you should chain on as many reactive calls as possible before resorting to block.

If you want to move over to a reactive application, then this is a very good way of slowly transferring an application, by slowly doing more and more reactive stuff and then calling block to return to the regular world.

Are you fully reactive? no, are you a blocking web server like before, well yes. Is it worse that RestTemplate most likely not. Are you better than before, from a maintenance standpoint, yes since spring has officially gone out with that there is not going to be any more updates to RestTemplate.

Is the mechanics behind blocking calls with WebClient similar to what RestTemplate does?

Well this is hard to tell, because RestTemplate is mainly just a wrapper around the HttpClient provided by the underlying server implementation.

How the blocking is written is probably different, but what they do in the end, is most likely the same. A Mono<T> blocks using a CountDownLatch with repeated calls to getCount and then inbetween blocks with a call on latch await until the response is back. I havn't looked at the different HttpClients that RestTemplate is wrapping, you need to read up on each of them (tomcat, jetty, undertow, etc. etc.)

Is there a possibility that the performance would be worse than in case I just use RestTemplate?

This is extremely hard to tell because performance is not black and white. It all depends on hardware, what type of jobs are to be done, how the code is written, thread pool sizes, operating system etc..

Netty is a fully event driven server and it is starting to become the de facto standard of web server in the Java community. Undertow decided to switch out their entire core to the netty core, because it was so good, and easier to maintain.

As Netty is event driven, running it as an old server with one thread per request could hurt performance since it is not optimized for that type of work, but on the other hand when you run it fully event driven it will shine.

The only way to answer this, is to do your own benchmarks, we can't answer that for you.

If you want to know more about how netty actually works under the hood a recommend reading the book Netty in Action which is not free but very good read to understand the innerworkings of Netty and its async threading model.

Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
Toerktumlare
  • 12,548
  • 3
  • 35
  • 54
  • 1
    Thanks, I think this is the kind of answer I was expecting. I'd upvote it but don't have enough reputation:( Nevertheless you were very helpful and I appreciate the time you spent on it! – tracer_13 Feb 16 '22 at 12:51
  • 1
    Just a small correction: the `await` link goes to a test util method. That's not how `block` is implemented. The real implementation uses a `CountDownLatch`. – Martin Tarjányi Feb 16 '22 at 20:52
  • that is true, updated the link – Toerktumlare Feb 16 '22 at 23:45
  • "which pauses at CountDownLatch#await until there are no threads left" - What do you mean by "no threads left"? It waits until the first next/complete/error event. – Martin Tarjányi Feb 17 '22 at 19:45
  • I know how CountDownLatch works. That's why I asked the question because it wasn't clear for me what threads you are referring to. I found that a bit confusing. I'll add my edit. Thank you for the opportunity. Otherwise a great answer! – Martin Tarjányi Feb 17 '22 at 20:30
2

In our applications we are migrating from RestTemplate to WebClient without any issues, .block() works just fine

Response response = this.webClient
        .post()
        .uri(uri)
        .body(fromValue)
        .retrieve()
        .bodyToMono(Response.class)
        .timeout(Duration.ofMillis(timeoutMillis))
        .block();

This is doing the same as RestTemplate does, it's sending the request in a synchronized way, and we have it working in PROD since a couple of months without any issues

Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
  • Thanks for your reply! So I suppose it's ok in general to block threads in WebClient and nothing to be afraid of, unless it's done in a reactive application? – tracer_13 Feb 15 '22 at 14:59
  • Right, I don't know what happens with a `.block()` in a reactive application. For reactive apps we use Mono<> responses – Ramiro Higonet Lang Feb 15 '22 at 15:47
  • Just wondering - wouldn't we exhaust the web client's thread pool if for example there will not be responses for a long period of time and we use requests without the timeout? Is it really okay to use a timeout to terminate the request threads? Maybe I'm wrong, I'm doing parallels to the CompletableFuture and another asynchronous framework such as Play! where it is really bad idea and conceptually wrong to block or time out the requests as it leads to performance degradation and makes no sense in use of reactive client at all? – AnMi Feb 15 '22 at 19:28
  • Yes for sure, having several requests at the same time without timeout would exhaust the pool, that's why we use a timeout. For our use case, this works perfectly, but for sure it wouldn't be ideal for other use cases. For that scenario, I would recommend using WebClient in an asynchronous way – Ramiro Higonet Lang Feb 15 '22 at 19:36
  • 2
    Please don't do this. This brings no value whatsoever to your application when compared to the good old `RestTemplate`. – João Dias Feb 15 '22 at 22:34
  • That is your opinion Which is simply not true. Springs recommendation is to move forward with webclient, as resttemplate is in maintnance mode. – Toerktumlare Feb 16 '22 at 07:40
  • This brings no value, but also doesn't do anything bad? @JoãoDias – tracer_13 Feb 16 '22 at 07:40
  • also if you wish to use timouts dont use duration, this is how you configure it https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-client-builder-reactor-timeout – Toerktumlare Feb 16 '22 at 07:49
  • 1
    @tracer_13 it isn't bad, but I would stick with `RestTemplate` until it is deprecated at any point in time. Using `WebClient` in a non-reactive application brings little value to it (depending on how you use it, but as depicted in this answer it has no additional value) and makes it harder to read. Using `block()` in a reactive application is worse and that was what I thought you were doing. – João Dias Feb 16 '22 at 10:23
  • Thanks for your input! Harder to read is indeed a personal preference, but I get your general idea :) – tracer_13 Feb 16 '22 at 10:53
0

It is worth adding to the previous responses that if you want to use webClient in a blocking way while using only spring-boot-starter-webflux dependency, will throw an exception like block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3, so in order to use Webclient in a blocking way you need to configure a spring MVC application by adding spring-boot-starter-web as stated in the documentation Web Environment:

A SpringApplication attempts to create the right type of ApplicationContext on your behalf. The algorithm used to determine a WebApplicationType is the following:

If Spring MVC is present, an AnnotationConfigServletWebServerApplicationContext is used

If Spring MVC is not present and Spring WebFlux is present, an AnnotationConfigReactiveWebServerApplicationContext is used

Otherwise, AnnotationConfigApplicationContext is used

This means that if you are using Spring MVC and the new WebClient from Spring WebFlux in the same application, Spring MVC will be used by default. You can override that easily by calling setWebApplicationType(WebApplicationType).

-1

RestTemplate and WebClient are both popular libraries in the Java ecosystem used for making HTTP requests, particularly in Spring-based applications. They serve the same purpose of communicating with RESTful APIs or other HTTP-based services, but they have different designs and characteristics. Here are some key differences between them:

  1. Synchronous vs. Asynchronous:

    • RestTemplate: It is a synchronous HTTP client, meaning that when you make a request, the thread making the request will wait until the response is received before proceeding further. This can potentially lead to blocking and decreased application performance in scenarios where you have high concurrency or slow network connections.
    • WebClient: It is an asynchronous HTTP client introduced in Spring WebFlux, which is built on top of Project Reactor. It allows you to make non-blocking, asynchronous requests, making it more suitable for high-concurrency scenarios and reactive programming.
  2. Reactive Support:

    • RestTemplate: It does not natively support reactive programming. If you want to use reactive features, you would need to wrap the RestTemplate calls in reactive code using Mono or Flux (from Reactor).
    • WebClient: It is designed with reactive support from the ground up. It returns reactive types like Mono and Flux directly, which can seamlessly integrate with other reactive components in Spring WebFlux.
  3. Dependencies:

    • RestTemplate: It is part of the Spring Web module, which means it is available in applications using Spring MVC (Servlet-based) or Spring Boot with traditional servlet containers.
    • WebClient: It is also part of the Spring WebFlux module. To use WebClient, you need to have Spring WebFlux on your classpath. Spring WebFlux is designed for building reactive, non-blocking applications and can be used with servlet containers or Netty.
  4. Ease of Use:

    • RestTemplate: It has been available since older versions of Spring and is widely used in many projects. Its API is more familiar and might be easier to start with for developers already familiar with traditional synchronous programming.
    • WebClient: The API of WebClient might feel a bit more complex due to its reactive nature, especially if you're not familiar with reactive programming concepts. However, it provides powerful and flexible features for reactive applications.
  5. Future Development:

    • RestTemplate: Since Spring WebFlux and WebClient are part of Spring's reactive ecosystem, it is likely that future enhancements and features will be more focused on WebClient, and RestTemplate might become less prominent over time.
    • WebClient: It is the recommended choice for building reactive applications with Spring WebFlux. As such, it is more likely to receive ongoing improvements and optimizations.

In summary, if you are working on a traditional Spring MVC application and don't require reactive programming, RestTemplate could be a straightforward choice. However, if you are building a reactive application with Spring WebFlux, or if you need non-blocking, asynchronous behavior, WebClient is the more appropriate option.

Aman Garg
  • 3,122
  • 4
  • 24
  • 32