i've Eureka cluster with multiple servers:
#ENV
EUREKA_URL=http://host1:8761/eureka/,http://host2:8761/eureka/,http://host3:8761/eureka/
#boostrap.yml
eureka:
client:
registryFetchIntervalSeconds: 5
serviceUrl:
defaultZone: ${EUREKA_URL:http://127.0.0.1:8761/eureka/}
And in case, when host1 is down, my app doesn't start with exception:
13410 2021-01-14 11:28:34,994 ERROR [ main ] o.s.b.SpringApplication | Application run failed
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://host1:8761/eureka/apps/": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:748)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:674)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:583)
at org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient.getApplicationsInternal(RestTemplateEurekaHttpClient.java:154)
at org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient.getApplications(RestTemplateEurekaHttpClient.java:142)
at org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapConfiguration.lambda$eurekaConfigServerInstanceProvider$0(EurekaConfigServerBootstrapConfiguration.java:112)
at org.springframework.cloud.config.client.ConfigServerInstanceProvider.getConfigServerInstances(ConfigServerInstanceProvider.java:50)
at org.springframework.cloud.config.client.ConfigServerInstanceProvider$$FastClassBySpringCGLIB$$facbf882.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
at
It's strange situation for me, because i expected that eureka will try to connect to other servers, but it's not so. I found it in spring-cloud-netflix-eureka-client-2.2.3.RELEASE.jar
:
// EurekaConfigServerBootstrapConfiguration.java
private String getEurekaUrl(EurekaClientConfigBean config) {
List<String> urls = EndpointUtils.getServiceUrlsFromConfig(config,
EurekaClientConfigBean.DEFAULT_ZONE, true);
return urls.get(0);
}
and
// DefaultEurekaClientConfig.java
@Override
public List<String> getEurekaServerServiceUrls(String myZone) {
String serviceUrls = configInstance.getStringProperty(
namespace + CONFIG_EUREKA_SERVER_SERVICE_URL_PREFIX + "." + myZone, null).get();
if (serviceUrls == null || serviceUrls.isEmpty()) {
serviceUrls = configInstance.getStringProperty(
namespace + CONFIG_EUREKA_SERVER_SERVICE_URL_PREFIX + ".default", null).get();
}
if (serviceUrls != null) {
return Arrays.asList(serviceUrls.split(URL_SEPARATOR));
}
return new ArrayList<String>();
}
and finally:
// RestTemplateEurekaHttpClient.java
private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath,
String[] regions) {
String url = serviceUrl + urlPath;
if (regions != null && regions.length > 0) {
url = url + (urlPath.contains("?") ? "&" : "?") + "regions="
+ StringUtil.join(regions);
}
// There is no exception handling here and above!
ResponseEntity<EurekaApplications> response = restTemplate.exchange(url,
HttpMethod.GET, null, EurekaApplications.class);
return anEurekaHttpResponse(response.getStatusCodeValue(),
response.getStatusCode().value() == HttpStatus.OK.value()
&& response.hasBody() ? (Applications) response.getBody() : null)
.headers(headersOf(response)).build();
}
I've java11
, springBootVersion = '2.3.4.RELEASE'
, spring-cloud-netflix-eureka-client-2.2.3.RELEASE
, eureka-client-1.9.21
.
How I can make it so that eureka, in case of unsuccessful registration on the first server, continues to try on the following servers? Any idea?
I found workaround. I just override bean:
@Slf4j
@Configuration
public class EurekaMultiClientBoostrapConfig {
@Bean
@Primary
public RestTemplateEurekaHttpClient configDiscoveryRestTemplateEurekaHttpClient(EurekaClientConfigBean config) {
List<String> urls = EndpointUtils.getServiceUrlsFromConfig(config,
EurekaClientConfigBean.DEFAULT_ZONE, true);
for (String url : urls) {
try {
RestTemplateEurekaHttpClient client = (RestTemplateEurekaHttpClient) new RestTemplateTransportClientFactory()
.newClient(new DefaultEndpoint(url));
client.getApplications(config.getRegion());
log.info("Registered on Eureka host '{}' is successful.", url);
return client;
} catch (Exception e) {
log.warn("Eureka host '{}' is unavailable(reason: {})", url, e.getMessage());
}
}
throw new IllegalStateException("Failed to register on any eureka host.");
}
P.S. Since this configuration belongs to the Bootstrap Configuration, don't forget add following param to resources/META-INF/spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration=your.app.package.EurekaMultiClientBoostrapConfig