com.netflix.eureka.transport.Jersey2ReplicationClient Maven / Gradle / Ivy
package com.netflix.eureka.transport;
import static com.netflix.discovery.shared.transport.EurekaHttpResponse.anEurekaHttpResponse;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
import com.netflix.discovery.shared.transport.EurekaHttpResponse;
import com.netflix.discovery.shared.transport.jersey2.AbstractJersey2EurekaHttpClient;
import com.netflix.discovery.shared.transport.jersey2.EurekaIdentityHeaderFilter;
import com.netflix.discovery.shared.transport.jersey2.EurekaJersey2Client;
import com.netflix.discovery.shared.transport.jersey2.EurekaJersey2ClientImpl;
import com.netflix.eureka.EurekaServerConfig;
import com.netflix.eureka.EurekaServerIdentity;
import com.netflix.eureka.cluster.HttpReplicationClient;
import com.netflix.eureka.cluster.PeerEurekaNode;
import com.netflix.eureka.cluster.protocol.ReplicationList;
import com.netflix.eureka.cluster.protocol.ReplicationListResponse;
import com.netflix.eureka.resources.ASGResource.ASGStatus;
import com.netflix.eureka.resources.ServerCodecs;
/**
* @author Tomasz Bak
*/
public class Jersey2ReplicationClient extends AbstractJersey2EurekaHttpClient implements HttpReplicationClient {
private static final Logger logger = LoggerFactory.getLogger(Jersey2ReplicationClient.class);
private final EurekaJersey2Client eurekaJersey2Client;
public Jersey2ReplicationClient(EurekaJersey2Client eurekaJersey2Client, String serviceUrl) {
super(eurekaJersey2Client.getClient(), serviceUrl);
this.eurekaJersey2Client = eurekaJersey2Client;
}
@Override
protected void addExtraHeaders(Builder webResource) {
webResource.header(PeerEurekaNode.HEADER_REPLICATION, "true");
}
/**
* Compared to regular heartbeat, in the replication channel the server may return a more up to date
* instance copy.
*/
@Override
public EurekaHttpResponse sendHeartBeat(String appName, String id, InstanceInfo info, InstanceStatus overriddenStatus) {
String urlPath = "apps/" + appName + '/' + id;
Response response = null;
try {
WebTarget webResource = jerseyClient.target(serviceUrl)
.path(urlPath)
.queryParam("status", info.getStatus().toString())
.queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString());
if (overriddenStatus != null) {
webResource = webResource.queryParam("overriddenstatus", overriddenStatus.name());
}
Builder requestBuilder = webResource.request();
addExtraHeaders(requestBuilder);
response = requestBuilder.accept(MediaType.APPLICATION_JSON_TYPE).put(Entity.entity("{}", MediaType.APPLICATION_JSON_TYPE)); // Jersey2 refuses to handle PUT with no body
InstanceInfo infoFromPeer = null;
if (response.getStatus() == Status.CONFLICT.getStatusCode() && response.hasEntity()) {
infoFromPeer = response.readEntity(InstanceInfo.class);
}
return anEurekaHttpResponse(response.getStatus(), infoFromPeer).type(MediaType.APPLICATION_JSON_TYPE).build();
} finally {
if (logger.isDebugEnabled()) {
logger.debug("[heartbeat] Jersey HTTP PUT {}; statusCode={}", urlPath, response == null ? "N/A" : response.getStatus());
}
if (response != null) {
response.close();
}
}
}
@Override
public EurekaHttpResponse statusUpdate(String asgName, ASGStatus newStatus) {
Response response = null;
try {
String urlPath = "asg/" + asgName + "/status";
response = jerseyClient.target(serviceUrl)
.path(urlPath)
.queryParam("value", newStatus.name())
.request()
.header(PeerEurekaNode.HEADER_REPLICATION, "true")
.put(Entity.text(""));
return EurekaHttpResponse.status(response.getStatus());
} finally {
if (response != null) {
response.close();
}
}
}
@Override
public EurekaHttpResponse submitBatchUpdates(ReplicationList replicationList) {
Response response = null;
try {
response = jerseyClient.target(serviceUrl)
.path(PeerEurekaNode.BATCH_URL_PATH)
.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.json(replicationList));
if (!isSuccess(response.getStatus())) {
return anEurekaHttpResponse(response.getStatus(), ReplicationListResponse.class).build();
}
ReplicationListResponse batchResponse = response.readEntity(ReplicationListResponse.class);
return anEurekaHttpResponse(response.getStatus(), batchResponse).type(MediaType.APPLICATION_JSON_TYPE).build();
} finally {
if (response != null) {
response.close();
}
}
}
@Override
public void shutdown() {
super.shutdown();
eurekaJersey2Client.destroyResources();
}
public static Jersey2ReplicationClient createReplicationClient(EurekaServerConfig config, ServerCodecs serverCodecs, String serviceUrl) {
String name = Jersey2ReplicationClient.class.getSimpleName() + ": " + serviceUrl + "apps/: ";
EurekaJersey2Client jerseyClient;
try {
String hostname;
try {
hostname = new URL(serviceUrl).getHost();
} catch (MalformedURLException e) {
hostname = serviceUrl;
}
String jerseyClientName = "Discovery-PeerNodeClient-" + hostname;
EurekaJersey2ClientImpl.EurekaJersey2ClientBuilder clientBuilder = new EurekaJersey2ClientImpl.EurekaJersey2ClientBuilder()
.withClientName(jerseyClientName)
.withUserAgent("Java-EurekaClient-Replication")
.withEncoderWrapper(serverCodecs.getFullJsonCodec())
.withDecoderWrapper(serverCodecs.getFullJsonCodec())
.withConnectionTimeout(config.getPeerNodeConnectTimeoutMs())
.withReadTimeout(config.getPeerNodeReadTimeoutMs())
.withMaxConnectionsPerHost(config.getPeerNodeTotalConnectionsPerHost())
.withMaxTotalConnections(config.getPeerNodeTotalConnections())
.withConnectionIdleTimeout(config.getPeerNodeConnectionIdleTimeoutSeconds());
if (serviceUrl.startsWith("https://") &&
"true".equals(System.getProperty("com.netflix.eureka.shouldSSLConnectionsUseSystemSocketFactory"))) {
clientBuilder.withSystemSSLConfiguration();
}
jerseyClient = clientBuilder.build();
} catch (Throwable e) {
throw new RuntimeException("Cannot Create new Replica Node :" + name, e);
}
String ip = null;
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
logger.warn("Cannot find localhost ip", e);
}
Client jerseyApacheClient = jerseyClient.getClient();
jerseyApacheClient.register(new Jersey2DynamicGZIPContentEncodingFilter(config));
EurekaServerIdentity identity = new EurekaServerIdentity(ip);
jerseyApacheClient.register(new EurekaIdentityHeaderFilter(identity));
return new Jersey2ReplicationClient(jerseyClient, serviceUrl);
}
private static boolean isSuccess(int statusCode) {
return statusCode >= 200 && statusCode < 300;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy