Closed spencergibb closed 6 years ago
Please open a separate issue with the code in a zip file or in a git repo
I think this issue is related to the fact, that you're building the WebClient too early (in constructor).
org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancerAutoConfiguration is responsible for customizing the WebClient.Builder instances with LoadBalancerExchangeFilterFunction, which provides load balancing. From what I learned, ReactiveLoadBalancerAutoConfiguration runs after WebClient.Builders are injected (for example in your controllers).
The simple workaround is creating your clients when they are used (for example inside request handler method), not during initialization (since ReactiveLoadBalancerAutoConfiguration will be actually able to customize builders).
Is this a desired behaviour?
I've put together a quick code snippet:
@Controller
class BuggedController {
private final WebClient webClient;
@Autowired
public BuggedController(WebClient.Builder lbWebClientBuilder) {
// lbWebClientBuilder is not yet customized by ReactiveLoadBalancerAutoConfiguration
this.webClient = lbWebClientBuilder.build();
}
@GetMapping("/")
public Mono<?> handle() {
// no load-balancing here
return webClient.post().exchange(); // ...
}
}
@Controller
class WorkingController {
private final WebClient.Builder webClientBuilder;
@Autowired
public WorkingController(WebClient.Builder lbWebClientBuilder) {
this.webClientBuilder = lbWebClientBuilder;
}
@GetMapping("/")
public Mono<?> handle() {
// working load-balancing
return webClientBuilder.build().post().exchange(); // ...
}
}
@wojcikt This is indeed a working solution, however not desirable in many cases. Recreating WebClient
on every request is quite wasteful and there are cases when some other service requires to have WebClient
dependency.
The reason why @LoadBalanced
works for RestTemplate
is that LoadBalancerAutoConfiguration
works directly with the RestTemplate
bean opposed to ReactiveLoadBalancerAutoConfiguration
which works with the builder, this due to the fact that WebClient
is immutable and can't be extended after creation like RestTemplate
.
Here is a quick workaround:
@Bean
WebClient webClient(LoadBalancerClient loadBalancerClient) {
return WebClient.builder()
.filter(new LoadBalancerExchangeFilterFunction(loadBalancerClient))
.build();
}
This is essentially what happens in ReactiveLoadBalancerAutoConfiguration
.
Note! If you have other WebClientCustomizer
s in your project, you'll have to include them manually as well.
@robertt1234 your workaround saved my day. This small differences between Reactive and non reactive Spring make sometimes really difficult to work with Reactive API
Hi, when I create a @LoadBalanced WebClient build like this:
and want to use it for Spring Eureka I still get the following Exception:
The code, which uses this looks like this:
While the version with the RestTemplate, which also has been created with @LoadBalanced, works totally fine the one with the WebClient does not.
I don't see anything wrong according to the documentation of your commit.