Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebClient resultMono.block() blocks application if called from RestController [SPR-16186] #20734

Closed
spring-projects-issues opened this issue Nov 10, 2017 · 3 comments
Assignees
Labels
in: web

Comments

@spring-projects-issues
Copy link
Collaborator

@spring-projects-issues spring-projects-issues commented Nov 10, 2017

Semen Goryachkin opened SPR-16186 and commented

WebClient resultMono.block() blocks application if called from RestController.
In this case the browser does not receive a response from the server and the application stops responding to requests.

Example:

@RestController
public class WebClientController {
...
	@GetMapping(path = "/people1/{id}")
	public String getPeopleBlock(@PathVariable Long id) {
		System.out.println("People block request: " + id);
		return getPeopleRsp(id).block();
	}

	private Mono<String> getPeopleRsp(Long id) {
		String url = "https://swapi.co/api/people/" + id + "?format=json";
		return webClient.get().uri(url).accept(MediaType.APPLICATION_JSON_UTF8).header("User-Agent", "Chrome")
				.exchange().log().flatMap(r -> r.bodyToMono(String.class));
	}
}

Full example code (simple boot app): https://github.com/sgoryachkin/webclient-example

System: Google Chrome, Windows 7, JDK 1.8

Log:

People request: 4
2017-11-10 18:19:23.303  INFO 14664 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.4             : onSubscribe(FluxSwitchIfEmpty.SwitchIfEmptySubscriber)
2017-11-10 18:19:23.303  INFO 14664 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.4             : request(unbounded)
2017-11-10 18:19:24.373  INFO 14664 --- [ctor-http-nio-4] reactor.Mono.SwitchIfEmpty.4             : onNext(org.springframework.web.reactive.function.client.DefaultClientResponse@7057bfd4)
2017-11-10 18:19:24.374  INFO 14664 --- [ctor-http-nio-4] reactor.Mono.SwitchIfEmpty.4             : onComplete()
People request: 4
2017-11-10 18:19:26.559  INFO 14664 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.6             : onSubscribe(FluxSwitchIfEmpty.SwitchIfEmptySubscriber)
2017-11-10 18:19:26.559  INFO 14664 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.6             : request(unbounded)
2017-11-10 18:19:27.736  INFO 14664 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.6             : onNext(org.springframework.web.reactive.function.client.DefaultClientResponse@2ddb2177)
2017-11-10 18:19:27.737  INFO 14664 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.6             : onComplete()
People block request: 4
2017-11-10 18:19:32.864  INFO 14664 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.8             : onSubscribe(FluxSwitchIfEmpty.SwitchIfEmptySubscriber)
2017-11-10 18:19:32.864  INFO 14664 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.8             : request(unbounded)
People block request: 4
2017-11-10 18:19:51.075  INFO 14664 --- [ctor-http-nio-4] reactor.Mono.SwitchIfEmpty.10            : onSubscribe(FluxSwitchIfEmpty.SwitchIfEmptySubscriber)
2017-11-10 18:19:51.075  INFO 14664 --- [ctor-http-nio-4] reactor.Mono.SwitchIfEmpty.10            : request(unbounded)

Affects: 5.0.1

Reference URL: https://github.com/sgoryachkin/webclient-example/blob/master/src/main/java/org/sego/webclient/example/WebClientController.java

Issue Links:

  • #20757 Webflux server sometimes block when receiving large post body
@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Nov 10, 2017

Rossen Stoyanchev commented

Why are you blocking? Really not a good idea on a server with 4 threads which are also shared with the WebClient by default.

From what I can see the response from https://swapi.co/api/people/4?format=json is a permanent redirect. The redirect location is the same URL but with a trailing slash. When I change the code to use that URL it works. When the controller blocks on the WebClient response it fails to follow the redirect and I'm not quite sure if this is expected behavior or not. smaldini or Violeta Georgieva any idea? There is something strange, even though blocking is clearly not a good idea it seems like it should be able to complete, shouldn't it?

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Nov 13, 2017

Semen Goryachkin commented

Thanks for your reply. I understand your comments about the blocking is bad practis and about shared WebClient.
I update URL to https://swapi.co/api/people/4/?format=json (with slash). As a result, the handler (with block()) completes only the first time. Next times the block() method does not complete.

People block request: 1
2017-11-13 18:55:56.134  INFO 12596 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.2             : onSubscribe(FluxSwitchIfEmpty.SwitchIfEmptySubscriber)
2017-11-13 18:55:56.135  INFO 12596 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.2             : request(unbounded)
2017-11-13 18:55:57.025  INFO 12596 --- [ctor-http-nio-1] reactor.Mono.SwitchIfEmpty.2             : onNext(org.springframework.web.reactive.function.client.DefaultClientResponse@34873b94)
2017-11-13 18:55:57.034  INFO 12596 --- [ctor-http-nio-1] reactor.Mono.SwitchIfEmpty.2             : onComplete()
People block request: 2
2017-11-13 18:56:01.823  INFO 12596 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.4             : onSubscribe(FluxSwitchIfEmpty.SwitchIfEmptySubscriber)
2017-11-13 18:56:01.823  INFO 12596 --- [ctor-http-nio-2] reactor.Mono.SwitchIfEmpty.4             : request(unbounded)
People block request: 4
2017-11-13 19:07:25.619  INFO 12596 --- [ctor-http-nio-3] reactor.Mono.SwitchIfEmpty.6             : onSubscribe(FluxSwitchIfEmpty.SwitchIfEmptySubscriber)
2017-11-13 19:07:25.620  INFO 12596 --- [ctor-http-nio-3] reactor.Mono.SwitchIfEmpty.6             : request(unbounded)

This is reproduced in the RestController handler only. For example this code works good:

@RestController
public class WebClientController {

	@Autowired
	protected WebClient webClient;
	
	// Works
	@PostConstruct
	public void foo() {
		System.out.println(getPeopleRsp(2l).block());
		System.out.println(getPeopleRsp(3l).block());
		System.out.println(getPeopleRsp(4l).block());
		System.out.println(getPeopleRsp(5l).block());
	}
...
	private Mono<String> getPeopleRsp(Long id) {
		String url = "https://swapi.co/api/people/" + id + "/?format=json";
		return webClient.get().uri(url).accept(MediaType.APPLICATION_JSON_UTF8).header("User-Agent", "Chrome")
				.exchange().log().flatMap(r -> r.bodyToMono(String.class));
	}
...

@spring-projects-issues
Copy link
Collaborator Author

@spring-projects-issues spring-projects-issues commented Jan 11, 2018

Rossen Stoyanchev commented

I can no longer reproduce this with Boot 2.0.0.BUILD-SNAPSHOT (Reactor Netty 0.7.3 snapshot). I tried both with and without the trailing slash. On the startup the PostConstruct method completes the 4 requests, and after that I use curl from the command line to send several more to "/people1/{id}". There were a lot of issues resolved in Reactor 0.7.2 and 0.7.3 so this is not unexpected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web
Projects
None yet
Development

No branches or pull requests

2 participants