BAEL-4685 (#10418)
* Add code examples for article BAEL-4685 * Add tests for the endpoints. * Rename RequestTimeoutTests.java to RequestTimeoutUnitTest.java
This commit is contained in:
parent
c9bc95a5e2
commit
eea3ae3084
|
@ -19,6 +19,10 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.springfox</groupId>
|
<groupId>io.springfox</groupId>
|
||||||
<artifactId>springfox-swagger2</artifactId>
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
|
@ -29,6 +33,19 @@
|
||||||
<artifactId>springfox-swagger-ui</artifactId>
|
<artifactId>springfox-swagger-ui</artifactId>
|
||||||
<version>${swagger2.version}</version>
|
<version>${swagger2.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.resilience4j</groupId>
|
||||||
|
<artifactId>resilience4j-timelimiter</artifactId>
|
||||||
|
<version>1.6.1</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package com.baeldung.requesttimeout;
|
||||||
|
|
||||||
|
import com.baeldung.requesttimeout.domain.Book;
|
||||||
|
import com.baeldung.requesttimeout.domain.BookRepository;
|
||||||
|
import io.github.resilience4j.timelimiter.TimeLimiter;
|
||||||
|
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class RequestTimeoutRestController {
|
||||||
|
|
||||||
|
private final BookRepository bookRepository;
|
||||||
|
private final WebClient webClient;
|
||||||
|
|
||||||
|
public RequestTimeoutRestController(BookRepository bookRepository, WebClient webClient) {
|
||||||
|
this.bookRepository = bookRepository;
|
||||||
|
this.webClient = webClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/author/transactional")
|
||||||
|
@Transactional(timeout = 1)
|
||||||
|
public String getWithTransactionTimeout(@RequestParam String title) {
|
||||||
|
return getAuthor(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final TimeLimiter ourTimeLimiter = TimeLimiter.of(TimeLimiterConfig.custom().timeoutDuration(Duration.ofMillis(500)).build());
|
||||||
|
@GetMapping("/author/resilience4j")
|
||||||
|
public Callable<String> getWithResilience4jTimeLimiter(@RequestParam String title) {
|
||||||
|
return TimeLimiter.decorateFutureSupplier(ourTimeLimiter, () -> CompletableFuture.supplyAsync(() -> getAuthor(title)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/author/mvc-request-timeout")
|
||||||
|
public Callable<String> getWithMvcRequestTimeout(@RequestParam String title) {
|
||||||
|
return () -> getAuthor(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/author/webclient")
|
||||||
|
public String getWithWebClient(@RequestParam String title) {
|
||||||
|
return webClient.get()
|
||||||
|
.uri(uriBuilder -> uriBuilder
|
||||||
|
.path("/author/transactional")
|
||||||
|
.queryParam("title", title)
|
||||||
|
.build())
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class)
|
||||||
|
.block();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getAuthor(String title) {
|
||||||
|
bookRepository.wasteTime();
|
||||||
|
return bookRepository.findById(title).map(Book::getAuthor).orElse("No book found for this title.");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.baeldung.requesttimeout.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
import reactor.netty.http.client.HttpClient;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebClientConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebClient webClient() {
|
||||||
|
return WebClient.builder()
|
||||||
|
.baseUrl("http://localhost:8080")
|
||||||
|
.clientConnector(new ReactorClientHttpConnector(HttpClient.create().responseTimeout(Duration.ofMillis(250))))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.baeldung.requesttimeout.domain;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Book {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String title;
|
||||||
|
private String author;
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(String author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.baeldung.requesttimeout.domain;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface BookRepository extends JpaRepository<Book, String> {
|
||||||
|
|
||||||
|
default int wasteTime() {
|
||||||
|
int i = Integer.MIN_VALUE;
|
||||||
|
while(i < Integer.MAX_VALUE) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
spring.mvc.async.request-timeout=750
|
|
@ -0,0 +1,46 @@
|
||||||
|
package com.baeldung.requesttimeout;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClient;
|
||||||
|
import org.springframework.web.reactive.function.client.WebClientRequestException;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
public class RequestTimeoutTests {
|
||||||
|
|
||||||
|
private static final WebClient WEB_CLIENT = WebClient.builder().baseUrl("http://localhost:8080").build();
|
||||||
|
|
||||||
|
@Test(expected = WebClientRequestException.class)
|
||||||
|
public void givenTransactionTimeout_whenTimeExpires_thenReceiveException() {
|
||||||
|
getAuthor("transactional");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = WebClientRequestException.class)
|
||||||
|
public void givenResilience4jTimeLimiter_whenTimeExpires_thenReceiveException() {
|
||||||
|
getAuthor("resilience4j");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = WebClientRequestException.class)
|
||||||
|
public void givenMvcRequestTimeout_whenTimeExpires_thenReceiveException() {
|
||||||
|
getAuthor("mvc-request-timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = WebClientRequestException.class)
|
||||||
|
public void givenWebClientTimeout_whenTimeExpires_thenReceiveException() {
|
||||||
|
getAuthor("webclient");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getAuthor(String authorPath) {
|
||||||
|
WEB_CLIENT.get()
|
||||||
|
.uri(uriBuilder -> uriBuilder
|
||||||
|
.path("/author/" + authorPath)
|
||||||
|
.queryParam("title", "title")
|
||||||
|
.build())
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(String.class)
|
||||||
|
.block();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
spring.mvc.async.request-timeout=750
|
Loading…
Reference in New Issue