Skip to content

Commit

Permalink
Client observations creating too many uri tag values; fixes spring-cl…
Browse files Browse the repository at this point in the history
  • Loading branch information
Soeren Unruh committed Jul 31, 2024
1 parent d82fd9f commit a5120e7
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package org.springframework.cloud.netflix.eureka.http;

import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -38,8 +37,8 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import static com.netflix.discovery.shared.transport.EurekaHttpResponse.anEurekaHttpResponse;

Expand Down Expand Up @@ -71,48 +70,39 @@ public RestTemplate getRestTemplate() {

@Override
public EurekaHttpResponse<Void> register(InstanceInfo info) {
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl)
.path("apps/{appName}")
.buildAndExpand(info.getAppName())
.toUri();
String urlPath = serviceUrl + "apps/{appName}";

HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);

ResponseEntity<Void> response = restTemplate.exchange(uri, HttpMethod.POST, new HttpEntity<>(info, headers),
Void.class);
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.POST, new HttpEntity<>(info, headers),
Void.class, info.getAppName());

return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build();
}

@Override
public EurekaHttpResponse<Void> cancel(String appName, String id) {
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl)
.path("apps/{appName}/{id}")
.buildAndExpand(appName, id)
.toUri();
String urlPath = serviceUrl + "apps/{appName}/{id}";

ResponseEntity<Void> response = restTemplate.exchange(uri, HttpMethod.DELETE, null, Void.class);
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.DELETE, null, Void.class, appName,
id);

return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build();
}

@Override
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info,
InstanceStatus overriddenStatus) {
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(serviceUrl)
.path("apps/{appName}/{id}")
.queryParam("status", info.getStatus().toString())
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString());
String urlPath = serviceUrl + "apps/{appName}/{id}?status={status}&lastDirtyTimestamp={lastDirtyTimestamp}";

if (overriddenStatus != null) {
uriBuilder = uriBuilder.queryParam("overriddenstatus", overriddenStatus.name());
urlPath = urlPath + "&overriddenstatus={overriddenStatus}";
}

URI uri = uriBuilder.buildAndExpand(appName, id).toUri();

ResponseEntity<InstanceInfo> response = restTemplate.exchange(uri, HttpMethod.PUT, null, InstanceInfo.class);
ResponseEntity<InstanceInfo> response = restTemplate.exchange(urlPath, HttpMethod.PUT, null, InstanceInfo.class,
appName, id, info.getStatus(), info.getLastDirtyTimestamp(), overriddenStatus);

EurekaHttpResponseBuilder<InstanceInfo> eurekaResponseBuilder = anEurekaHttpResponse(
response.getStatusCode().value(), InstanceInfo.class)
Expand All @@ -128,27 +118,21 @@ public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id,
@Override
public EurekaHttpResponse<Void> statusUpdate(String appName, String id, InstanceStatus newStatus,
InstanceInfo info) {
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl)
.path("apps/{appName}/{id}/status")
.queryParam("value", newStatus.name())
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString())
.buildAndExpand(appName, id)
.toUri();
String urlPath = serviceUrl
+ "apps/{appName}/{id}/status?value={value}&lastDirtyTimestamp={lastDirtyTimestamp}";

ResponseEntity<Void> response = restTemplate.exchange(uri, HttpMethod.PUT, null, Void.class);
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.PUT, null, Void.class, appName, id,
newStatus, info.getLastDirtyTimestamp());

return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build();
}

@Override
public EurekaHttpResponse<Void> deleteStatusOverride(String appName, String id, InstanceInfo info) {
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl)
.path("apps/{appName}/{id}/status")
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString())
.buildAndExpand(appName, id)
.toUri();
String urlPath = serviceUrl + "apps/{appName}/{id}/status?lastDirtyTimestamp={lastDirtyTimestamp}";

ResponseEntity<Void> response = restTemplate.exchange(uri, HttpMethod.DELETE, null, Void.class);
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.DELETE, null, Void.class, appName, id,
info.getLastDirtyTimestamp());

return anEurekaHttpResponse(response.getStatusCode().value()).headers(headersOf(response)).build();
}
Expand All @@ -158,17 +142,16 @@ public EurekaHttpResponse<Applications> getApplications(String... regions) {
return getApplicationsInternal("apps/", regions);
}

private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath, String[] regions) {
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(serviceUrl).path(urlPath);
private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath, String[] regions,
Object... uriVariables) {
String url = serviceUrl + urlPath;

if (regions != null && regions.length > 0) {
uriBuilder = uriBuilder.queryParam("regions", StringUtil.join(regions));
url = url + (urlPath.contains("?") ? "&" : "?") + "regions={regions}";
}

URI uri = uriBuilder.build().toUri();

ResponseEntity<EurekaApplications> response = restTemplate.exchange(uri, HttpMethod.GET, null,
EurekaApplications.class);
ResponseEntity<EurekaApplications> response = restTemplate.exchange(url, HttpMethod.GET, null,
EurekaApplications.class, ObjectUtils.addObjectToArray(uriVariables, StringUtil.join(regions)));

return anEurekaHttpResponse(response.getStatusCode().value(),
response.getStatusCode().value() == HttpStatus.OK.value() && response.hasBody()
Expand All @@ -184,19 +167,20 @@ public EurekaHttpResponse<Applications> getDelta(String... regions) {

@Override
public EurekaHttpResponse<Applications> getVip(String vipAddress, String... regions) {
return getApplicationsInternal("vips/" + vipAddress, regions);
return getApplicationsInternal("vips/{vipAddress}", regions, vipAddress);
}

@Override
public EurekaHttpResponse<Applications> getSecureVip(String secureVipAddress, String... regions) {
return getApplicationsInternal("svips/" + secureVipAddress, regions);
return getApplicationsInternal("svips/{secureVipAddress}", regions, secureVipAddress);
}

@Override
public EurekaHttpResponse<Application> getApplication(String appName) {
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).path("apps/{appName}").buildAndExpand(appName).toUri();
String urlPath = serviceUrl + "apps/{appName}";

ResponseEntity<Application> response = restTemplate.exchange(uri, HttpMethod.GET, null, Application.class);
ResponseEntity<Application> response = restTemplate.exchange(urlPath, HttpMethod.GET, null, Application.class,
appName);

Application application = response.getStatusCode().value() == HttpStatus.OK.value() && response.hasBody()
? response.getBody() : null;
Expand All @@ -206,18 +190,19 @@ public EurekaHttpResponse<Application> getApplication(String appName) {

@Override
public EurekaHttpResponse<InstanceInfo> getInstance(String appName, String id) {
return getInstanceInternal("apps", appName, id);
return getInstanceInternal("apps/{appName}/{id}", appName, id);
}

@Override
public EurekaHttpResponse<InstanceInfo> getInstance(String id) {
return getInstanceInternal("instances", id);
return getInstanceInternal("instances/{id}", id);
}

private EurekaHttpResponse<InstanceInfo> getInstanceInternal(String... pathSegments) {
URI uri = UriComponentsBuilder.fromHttpUrl(serviceUrl).pathSegment(pathSegments).build().toUri();
private EurekaHttpResponse<InstanceInfo> getInstanceInternal(String urlPath, Object... uriVariables) {
urlPath = serviceUrl + urlPath;

ResponseEntity<InstanceInfo> response = restTemplate.exchange(uri, HttpMethod.GET, null, InstanceInfo.class);
ResponseEntity<InstanceInfo> response = restTemplate.exchange(urlPath, HttpMethod.GET, null, InstanceInfo.class,
uriVariables);

return anEurekaHttpResponse(response.getStatusCode().value(),
response.getStatusCode().value() == HttpStatus.OK.value() && response.hasBody() ? response.getBody()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package org.springframework.cloud.netflix.eureka.http;

import java.util.Map;
import java.util.Optional;

import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
Expand All @@ -34,6 +33,7 @@
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
Expand All @@ -56,7 +56,7 @@ public WebClientEurekaHttpClient(WebClient webClient) {
@Override
public EurekaHttpResponse<Void> register(InstanceInfo info) {
return webClient.post()
.uri(uriBuilder -> uriBuilder.path("apps/{appName}").build(info.getAppName()))
.uri("apps/{appName}", info.getAppName())
.body(BodyInserters.fromValue(info))
.header(HttpHeaders.ACCEPT_ENCODING, "gzip")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
Expand All @@ -70,7 +70,7 @@ public EurekaHttpResponse<Void> register(InstanceInfo info) {
@Override
public EurekaHttpResponse<Void> cancel(String appName, String id) {
return webClient.delete()
.uri(uriBuilder -> uriBuilder.path("apps/{appName}/{id}").build(appName, id))
.uri("apps/{appName}/{id}", appName, id)
.retrieve()
.onStatus(HttpStatusCode::isError, this::ignoreError)
.toBodilessEntity()
Expand All @@ -83,10 +83,8 @@ public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id,
InstanceStatus overriddenStatus) {

ResponseEntity<InstanceInfo> response = webClient.put()
.uri(uriBuilder -> uriBuilder.path("apps/{appName}/{id}")
.queryParam("status", info.getStatus().toString())
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString())
.build(appName, id))
.uri("apps/{appName}/{id}?status={status}&lastDirtyTimestamp={lastDirtyTimestamp}", appName, id,
info.getStatus(), info.getLastDirtyTimestamp())
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.retrieve()
Expand All @@ -112,10 +110,8 @@ public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id,
public EurekaHttpResponse<Void> statusUpdate(String appName, String id, InstanceStatus newStatus,
InstanceInfo info) {
return webClient.put()
.uri(uriBuilder -> uriBuilder.path("apps/{appName}/{id}/status")
.queryParam("value", newStatus.name())
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString())
.build(appName, id))
.uri("apps/{appName}/{id}/status?value={value}&lastDirtyTimestamp={lastDirtyTimestamp}", appName, id,
newStatus, info.getLastDirtyTimestamp())
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.retrieve()
.onStatus(HttpStatusCode::isError, this::ignoreError)
Expand All @@ -127,9 +123,8 @@ public EurekaHttpResponse<Void> statusUpdate(String appName, String id, Instance
@Override
public EurekaHttpResponse<Void> deleteStatusOverride(String appName, String id, InstanceInfo info) {
return webClient.delete()
.uri(uriBuilder -> uriBuilder.path("apps/{appName}/{id}/status")
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString())
.build(appName, id))
.uri("apps/{appName}/{id}/status?lastDirtyTimestamp={lastDirtyTimestamp}", appName, id,
info.getLastDirtyTimestamp())
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.retrieve()
.onStatus(HttpStatusCode::isError, this::ignoreError)
Expand All @@ -143,12 +138,16 @@ public EurekaHttpResponse<Applications> getApplications(String... regions) {
return getApplicationsInternal("apps/", regions);
}

private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath, String[] regions) {
Optional<String> regionsParam = (regions != null && regions.length > 0) ? Optional.of(StringUtil.join(regions))
: Optional.empty();
private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath, String[] regions,
Object... uriVariables) {
String url = urlPath;

if (regions != null && regions.length > 0) {
url = url + (urlPath.contains("?") ? "&" : "?") + "regions={regions}";
}

ResponseEntity<Applications> response = webClient.get()
.uri(uriBuilder -> uriBuilder.path(urlPath).queryParamIfPresent("regions", regionsParam).build())
.uri(url, ObjectUtils.addObjectToArray(uriVariables, StringUtil.join(regions)))
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.retrieve()
Expand All @@ -172,19 +171,19 @@ public EurekaHttpResponse<Applications> getDelta(String... regions) {

@Override
public EurekaHttpResponse<Applications> getVip(String vipAddress, String... regions) {
return getApplicationsInternal("vips/" + vipAddress, regions);
return getApplicationsInternal("vips/{vipAddress}", regions, vipAddress);
}

@Override
public EurekaHttpResponse<Applications> getSecureVip(String secureVipAddress, String... regions) {
return getApplicationsInternal("svips/" + secureVipAddress, regions);
return getApplicationsInternal("svips/{secureVipAddress}", regions, secureVipAddress);
}

@Override
public EurekaHttpResponse<Application> getApplication(String appName) {

ResponseEntity<Application> response = webClient.get()
.uri(uriBuilder -> uriBuilder.path("apps/{appName}").build(appName))
.uri("apps/{appName}", appName)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.retrieve()
.onStatus(HttpStatusCode::isError, this::ignoreError)
Expand All @@ -201,17 +200,17 @@ public EurekaHttpResponse<Application> getApplication(String appName) {

@Override
public EurekaHttpResponse<InstanceInfo> getInstance(String appName, String id) {
return getInstanceInternal("apps", appName, id);
return getInstanceInternal("apps/{appName}/{id}", appName, id);
}

@Override
public EurekaHttpResponse<InstanceInfo> getInstance(String id) {
return getInstanceInternal("instances", id);
return getInstanceInternal("instances/{id}", id);
}

private EurekaHttpResponse<InstanceInfo> getInstanceInternal(String... pathSegments) {
private EurekaHttpResponse<InstanceInfo> getInstanceInternal(String urlPath, Object... uriVariables) {
ResponseEntity<InstanceInfo> response = webClient.get()
.uri(uriBuilder -> uriBuilder.pathSegment(pathSegments).build())
.uri(urlPath, uriVariables)
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.retrieve()
.onStatus(HttpStatusCode::isError, this::ignoreError)
Expand Down
Loading

0 comments on commit a5120e7

Please sign in to comment.