ApplicationResource
//服务实例注册
@POST
@Consumes({"application/json", "application/xml"})
public Response addInstance(InstanceInfo info,
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
logger.debug("Registering instance {} (replication={})", info.getId(), isReplication);
//省略部分代码
//"true".equals(isReplication) , 由其他eureka节点同步过来的则为true
registry.register(info, "true".equals(isReplication));
return Response.status(204).build(); // 204 to be backwards compatible
}
InstanceRegistry
@Override
public void register(final InstanceInfo info, final boolean isReplication) {
handleRegistration(info, resolveInstanceLeaseDuration(info), isReplication);
super.register(info, isReplication);
}
//获取实例过期时间
private int resolveInstanceLeaseDuration(final InstanceInfo info) {
//默认90s
int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS;
if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
//获取客户端传递过来的过期时间
leaseDuration = info.getLeaseInfo().getDurationInSecs();
}
return leaseDuration;
}
private void handleRegistration(InstanceInfo info, int leaseDuration,
boolean isReplication) {
log("register " + info.getAppName() + ", vip " + info.getVIPAddress()
+ ", leaseDuration " + leaseDuration + ", isReplication "
+ isReplication);
//发布EurekaInstanceRegisteredEvent
publishEvent(new EurekaInstanceRegisteredEvent(this, info, leaseDuration,
isReplication));
}
@Override
public boolean renew(final String appName, final String serverId,
boolean isReplication) {
log("renew " + appName + " serverId " + serverId + ", isReplication {}"
+ isReplication);
List<Application> applications = getSortedApplications();
//循环所有的服务实例,根据serverId找到对应的实例
for (Application input : applications) {
if (input.getName().equals(appName)) {
InstanceInfo instance = null;
for (InstanceInfo info : input.getInstances()) {
if (info.getId().equals(serverId)) {
instance = info;
break;
}
}
//发布续约事件
publishEvent(new EurekaInstanceRenewedEvent(this, appName, serverId,
instance, isReplication));
break;
}
}
return super.renew(appName, serverId, isReplication);
}
@Override
public boolean cancel(String appName, String serverId, boolean isReplication) {
//发布服务剔除事件
handleCancelation(appName, serverId, isReplication);
return super.cancel(appName, serverId, isReplication);
}
PeerAwareInstanceRegistryImpl
@Override
public void register(final InstanceInfo info, final boolean isReplication) {
//默认90s
int leaseDuration = Lease.DEFAULT_DURATION_IN_SECS;
//过期时间优先使用客户段传递过来的属性值
if (info.getLeaseInfo() != null && info.getLeaseInfo().getDurationInSecs() > 0) {
leaseDuration = info.getLeaseInfo().getDurationInSecs();
}
super.register(info, leaseDuration, isReplication);
//同步注册的服务信息给给其他eureka节点,发送请求调用其他eureka节点的addInstance逻辑
replicateToPeers(Action.Register, info.getAppName(), info.getId(), info, null, isReplication);
}
@Override
public boolean renew(final String appName, final String id, final boolean isReplication) {
if (super.renew(appName, id, isReplication)) {
//将该实例的心跳续约信息同步给其他eureka节点
replicateToPeers(Action.Heartbeat, appName, id, null, null, isReplication);
return true;
}
return false;
}
@Override
public boolean statusUpdate(final String appName, final String id,
final InstanceStatus newStatus, String lastDirtyTimestamp,
final boolean isReplication) {
if (super.statusUpdate(appName, id, newStatus, lastDirtyTimestamp, isReplication)) {
//同步给其他eureka节点
replicateToPeers(Action.StatusUpdate, appName, id, null, newStatus, isReplication);
return true;
}
return false;
}
@Override
public boolean cancel(final String appName, final String id,
final boolean isReplication) {
if (super.cancel(appName, id, isReplication)) {
//同步给其他eureka节点
replicateToPeers(Action.Cancel, appName, id, null, null, isReplication);
return true;
}
return false;
}
AbstractInstanceRegistry
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
read.lock();
try {
//使用服务名称获取到gMap (实例id 和 实例)
Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName());
REGISTER.increment(isReplication);
//gMap为空,说明是该服务第一个实例注册过来
if (gMap == null) {
//实例化一个新map
final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap<String, Lease<InstanceInfo>>();
//放入registry中
gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap);
if (gMap == null) {
gMap = gNewMap;
}
}
//使用实例id获取到实例
Lease<InstanceInfo> existingLease = gMap.get(registrant.getId());
// Retain the last dirty timestamp without overwriting it, if there is already a lease
//实例已经存在
if (existingLease != null && (existingLease.getHolder() != null)) {
//获取存在的实例最后的更新时间
Long existingLastDirtyTimestamp = existingLease.getHolder().getLastDirtyTimestamp();
//获取注册过来的实例的最后更新时间
Long registrationLastDirtyTimestamp = registrant.getLastDirtyTimestamp();
logger.debug("Existing lease found (existing={}, provided={}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);
// this is a > instead of a >= because if the timestamps are equal, we still take the remote transmitted
// InstanceInfo instead of the server local copy.
//如果存在的实例更新时间更晚,则将registrant 修改为 存在的
if (existingLastDirtyTimestamp > registrationLastDirtyTimestamp) {
logger.warn("There is an existing lease and the existing lease's dirty timestamp {} is greater" +
" than the one that is being registered {}", existingLastDirtyTimestamp, registrationLastDirtyTimestamp);
logger.warn("Using the existing instanceInfo instead of the new instanceInfo as the registrant");
registrant = existingLease.getHolder();
}
}
//实例不存在
else {
synchronized (lock) {
if (this.expectedNumberOfClientsSendingRenews > 0) {
//新的实例注册上来,则expectedNumberOfClientsSendingRenews 加一
this.expectedNumberOfClientsSendingRenews = this.expectedNumberOfClientsSendingRenews + 1;
//重新设置 服务端期望每分钟接受到的心跳续约的次数
updateRenewsPerMinThreshold();
}
}
logger.debug("No previous lease information found; it is new registration");
}
//实例化lease
Lease<InstanceInfo> lease = new Lease<InstanceInfo>(registrant, leaseDuration);
//如果有存在的实例
if (existingLease != null) {
//服务上线时间 设置为 存在的实例的
lease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
}
//向gmap中放入实例id和实例的映射关系
gMap.put(registrant.getId(), lease);
recentRegisteredQueue.add(new Pair<Long, String>(
System.currentTimeMillis(),
registrant.getAppName() + "(" + registrant.getId() + ")"));
if (!InstanceStatus.UNKNOWN.equals(registrant.getOverriddenStatus())) {
logger.debug("Found overridden status {} for instance {}. Checking to see if needs to be add to the "
+ "overrides", registrant.getOverriddenStatus(), registrant.getId());
if (!overriddenInstanceStatusMap.containsKey(registrant.getId())) {
logger.info("Not found overridden id {} and hence adding it", registrant.getId());
overriddenInstanceStatusMap.put(registrant.getId(), registrant.getOverriddenStatus());
}
}
//设置overriddenStatus
InstanceStatus overriddenStatusFromMap = overriddenInstanceStatusMap.get(registrant.getId());
if (overriddenStatusFromMap != null) {
logger.info("Storing overridden status {} from map", overriddenStatusFromMap);
registrant.setOverriddenStatus(overriddenStatusFromMap);
}
InstanceStatus overriddenInstanceStatus = getOverriddenInstanceStatus(registrant, existingLease, isReplication);
//设置实例状态
registrant.setStatusWithoutDirty(overriddenInstanceStatus);
//实例状态为UP
if (InstanceStatus.UP.equals(registrant.getStatus())) {
//更新实例上线时间
lease.serviceUp();
}
//ActionType设置为ADD
registrant.setActionType(ActionType.ADDED);
//加入到recentlyChangedQueue (客户段增量同步服务信息使用)
recentlyChangedQueue.add(new RecentlyChangedItem(lease));
registrant.setLastUpdatedTimestamp();
//清除readWriteCacheMap对应服务的缓存信息
invalidateCache(registrant.getAppName(), registrant.getVIPAddress(), registrant.getSecureVipAddress());
logger.info("Registered instance {}/{} with status {} (replication={})",
registrant.getAppName(), registrant.getId(), registrant.getStatus(), isReplication);
} finally {
read.unlock();
}
}
public boolean renew(String appName, String id, boolean isReplication) {
RENEW.increment(isReplication);
//根据服务名称获取到服务列表
Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
Lease<InstanceInfo> leaseToRenew = null;
if (gMap != null) {
//根据实例id获取到具体实例
leaseToRenew = gMap.get(id);
}
//实例不存在,返回false
if (leaseToRenew == null) {
RENEW_NOT_FOUND.increment(isReplication);
logger.warn("DS: Registry: lease doesn't exist, registering resource: {} - {}", appName, id);
return false;
}
else {
InstanceInfo instanceInfo = leaseToRenew.getHolder();
if (instanceInfo != null) {
//获取实例的overriddenInstanceStatus
InstanceStatus overriddenInstanceStatus = this.getOverriddenInstanceStatus(
instanceInfo, leaseToRenew, isReplication);
if (overriddenInstanceStatus == InstanceStatus.UNKNOWN) {
logger.info("Instance status UNKNOWN possibly due to deleted override for instance {}"
+ "; re-register required", instanceInfo.getId());
RENEW_NOT_FOUND.increment(isReplication);
return false;
}
//判断实例的status 和 overriddenInstanceStatus是否一致
if (!instanceInfo.getStatus().equals(overriddenInstanceStatus)) {
logger.info(
"The instance status {} is different from overridden instance status {} for instance {}. "
+ "Hence setting the status to overridden status", instanceInfo.getStatus().name(),
overriddenInstanceStatus.name(),
instanceInfo.getId());
//不一致,将status 修改为 overriddenInstanceStatus
instanceInfo.setStatusWithoutDirty(overriddenInstanceStatus);
}
}
renewsLastMin.increment();
//更新实例的lastUpdateTimestamp完成续约
leaseToRenew.renew();
return true;
}
}
@Override
public boolean statusUpdate(String appName, String id,
InstanceStatus newStatus, String lastDirtyTimestamp,
boolean isReplication) {
read.lock();
try {
STATUS_UPDATE.increment(isReplication);
//服务名称获取到服务实例列表
Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
Lease<InstanceInfo> lease = null;
if (gMap != null) {
//服务实例id获取到服务实例
lease = gMap.get(id);
}
//服务实例为空,直接返回false
if (lease == null) {
return false;
}
else {
//更新lease的lastUpdateTimestamp
lease.renew();
InstanceInfo info = lease.getHolder();
// Lease is always created with its instance info object.
// This log statement is provided as a safeguard, in case this invariant is violated.
if (info == null) {
logger.error("Found Lease without a holder for instance id {}", id);
}
//如果更新的状态 和 原本实例的状态不相等
if ((info != null) && !(info.getStatus().equals(newStatus))) {
//如果将实例状态更新为 UP
if (InstanceStatus.UP.equals(newStatus)) {
//如果serviceUpTimestamp为0 ,则更新lease的serviceUpTimestamp为当前时间
lease.serviceUp();
}
//记录实例的重写的状态
overriddenInstanceStatusMap.put(id, newStatus);
//更新overriddenStatus
info.setOverriddenStatus(newStatus);
long replicaDirtyTimestamp = 0;
//更新status
info.setStatusWithoutDirty(newStatus);
if (lastDirtyTimestamp != null) {
replicaDirtyTimestamp = Long.parseLong(lastDirtyTimestamp);
}
//如果请求携带的lastDirtyTimestamp 大于 本地实例的lastDirtyTimestamp 。则更新
if (replicaDirtyTimestamp > info.getLastDirtyTimestamp()) {
info.setLastDirtyTimestamp(replicaDirtyTimestamp);
}
//设置为actionType为modified
info.setActionType(ActionType.MODIFIED);
//加入到recentlyChangedQueue
recentlyChangedQueue.add(new RecentlyChangedItem(lease));
//更新实例的lastUpdatedTimestamp
info.setLastUpdatedTimestamp();
//清空readWriteCacheMap对应服务的缓存信息
invalidateCache(appName, info.getVIPAddress(), info.getSecureVipAddress());
}
return true;
}
} finally {
read.unlock();
}
}
@Override
public boolean cancel(String appName, String id, boolean isReplication) {
return internalCancel(appName, id, isReplication);
}
protected boolean internalCancel(String appName, String id, boolean isReplication) {
read.lock();
try {
CANCEL.increment(isReplication);
//根据服务名称获取服务列表实例
Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
Lease<InstanceInfo> leaseToCancel = null;
if (gMap != null) {
//从gMap移除该实例
leaseToCancel = gMap.remove(id);
}
recentCanceledQueue.add(new Pair<Long, String>(System.currentTimeMillis(), appName + "(" + id + ")"));
//从overriddenInstanceStatusMap移除该实例
InstanceStatus instanceStatus = overriddenInstanceStatusMap.remove(id);
if (instanceStatus != null) {
logger.debug("Removed instance id {} from the overridden map which has value {}", id, instanceStatus.name());
}
if (leaseToCancel == null) {
CANCEL_NOT_FOUND.increment(isReplication);
logger.warn("DS: Registry: cancel failed because Lease is not registered for: {}/{}", appName, id);
return false;
} else {
//更新evictionTimestamp
leaseToCancel.cancel();
InstanceInfo instanceInfo = leaseToCancel.getHolder();
String vip = null;
String svip = null;
if (instanceInfo != null) {
//设置actionType
instanceInfo.setActionType(ActionType.DELETED);
//加入到recentlyChangedQueue中
recentlyChangedQueue.add(new RecentlyChangedItem(leaseToCancel));
//设置lastUpdatedTimestamp
instanceInfo.setLastUpdatedTimestamp();
vip = instanceInfo.getVIPAddress();
svip = instanceInfo.getSecureVipAddress();
}
//清空readWriteCacheMap对应服务的缓存信息
invalidateCache(appName, vip, svip);
logger.info("Cancelled instance {}/{} (replication={})", appName, id, isReplication);
}
} finally {
read.unlock();
}
synchronized (lock) {
if (this.expectedNumberOfClientsSendingRenews > 0) {
//实例剔除了 expectedNumberOfClientsSendingRenews 减一
this.expectedNumberOfClientsSendingRenews = this.expectedNumberOfClientsSendingRenews - 1;
//重新设置 服务端期望每分钟接受到的心跳续约的次数
updateRenewsPerMinThreshold();
}
}
return true;
}
ApplicationsResource
//客户端获取服务列表信息(全量)
@GET
public Response getContainers(@PathParam("version") String version,
@HeaderParam(HEADER_ACCEPT) String acceptHeader,
@HeaderParam(HEADER_ACCEPT_ENCODING) String acceptEncoding,
@HeaderParam(EurekaAccept.HTTP_X_EUREKA_ACCEPT) String eurekaAccept,
@Context UriInfo uriInfo,
@Nullable @QueryParam("regions") String regionsStr) {
//省略部分代码
//构建cacheKey 从 缓存map中获取值 (readOnlyCacheMap,readWriteCacheMap)
Key cacheKey = new Key(Key.EntityType.Application,
//全量
ResponseCacheImpl.ALL_APPS,
keyType, CurrentRequestVersion.get(), EurekaAccept.fromString(eurekaAccept), regions
);
Response response;
//是否接受响应结果进行压缩
if (acceptEncoding != null && acceptEncoding.contains(HEADER_GZIP_VALUE)) {
//responseCache.getGZIP(cacheKey)获取服务信息
response = Response.ok(responseCache.getGZIP(cacheKey))
.header(HEADER_CONTENT_ENCODING, HEADER_GZIP_VALUE)
.header(HEADER_CONTENT_TYPE, returnMediaType)
.build();
} else {
response = Response.ok(responseCache.get(cacheKey))
.build();
}
CurrentRequestVersion.remove();
return response;
}
//客户端获取服务列表信息(增量)
@Path("delta")
@GET
public Response getContainerDifferential(
@PathParam("version") String version,
@HeaderParam(HEADER_ACCEPT) String acceptHeader,
@HeaderParam(HEADER_ACCEPT_ENCODING) String acceptEncoding,
@HeaderParam(EurekaAccept.HTTP_X_EUREKA_ACCEPT) String eurekaAccept,
@Context UriInfo uriInfo, @Nullable @QueryParam("regions") String regionsStr) {
//省略部分代码
Key cacheKey = new Key(Key.EntityType.Application,
//增量
ResponseCacheImpl.ALL_APPS_DELTA,
keyType, CurrentRequestVersion.get(), EurekaAccept.fromString(eurekaAccept), regions
);
final Response response;
if (acceptEncoding != null && acceptEncoding.contains(HEADER_GZIP_VALUE)) {
response = Response.ok(responseCache.getGZIP(cacheKey))
.header(HEADER_CONTENT_ENCODING, HEADER_GZIP_VALUE)
.header(HEADER_CONTENT_TYPE, returnMediaType)
.build();
} else {
response = Response.ok(responseCache.get(cacheKey)).build();
}
CurrentRequestVersion.remove();
return response;
}
ResponseCacheImpl
public byte[] getGZIP(Key key) {
//获取服务列表信息
Value payload = getValue(key, shouldUseReadOnlyResponseCache);
if (payload == null) {
return null;
}
//压缩
return payload.getGzipped();
}
@VisibleForTesting
//该方法细节看到上一篇文章
//从缓存map中获取到服务列表信息返回
Value getValue(final Key key, boolean useReadOnlyCache) {
Value payload = null;
try {
if (useReadOnlyCache) {
final Value currentPayload = readOnlyCacheMap.get(key);
if (currentPayload != null) {
payload = currentPayload;
} else {
payload = readWriteCacheMap.get(key);
readOnlyCacheMap.put(key, payload);
}
} else {
payload = readWriteCacheMap.get(key);
}
} catch (Throwable t) {
logger.error("Cannot get value for key : {}", key, t);
}
return payload;
}
InstanceResource
//服务实例心跳续约
@PUT
public Response renewLease(
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication,
@QueryParam("overriddenstatus") String overriddenStatus,
@QueryParam("status") String status,
@QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {
//是否为其他eureka节点同步过来的信息
boolean isFromReplicaNode = "true".equals(isReplication);
//服务续约
boolean isSuccess = registry.renew(app.getName(), id, isFromReplicaNode);
if (!isSuccess) {
logger.warn("Not Found (Renew): {} - {}", app.getName(), id);
//返回 NOT_FOUND 404 , 客户端收到该状态码则重新调用服务端注册流程
return Response.status(Status.NOT_FOUND).build();
}
// Check if we need to sync based on dirty time stamp, the client
// instance might have changed some value
Response response;
//syncWhenTimestampDiffers默认为true
if (lastDirtyTimestamp != null && serverConfig.shouldSyncWhenTimestampDiffers()) {
response = this.validateDirtyTimestamp(Long.valueOf(lastDirtyTimestamp), isFromReplicaNode);
// Store the overridden status since the validation found out the node that replicates wins
if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()
&& (overriddenStatus != null)
&& !(InstanceStatus.UNKNOWN.name().equals(overriddenStatus))
&& isFromReplicaNode) {
registry.storeOverriddenStatusIfRequired(app.getAppName(), id, InstanceStatus.valueOf(overriddenStatus));
}
} else {
response = Response.ok().build();
}
logger.debug("Found (Renew): {} - {}; reply status={}", app.getName(), id, response.getStatus());
return response;
}
private Response validateDirtyTimestamp(Long lastDirtyTimestamp,
boolean isReplication) {
//根据服务名称和实例id获取到实例
InstanceInfo appInfo = registry.getInstanceByAppAndId(app.getName(), id, false);
//lastDirtyTimestamp(实例最后一次被修改的时间)
if (appInfo != null) {
//如果 本次续约携带的lastDirtyTimestamp 和 实例的lastDirtyTimestamp 不一致,正常情况下一致。
if ((lastDirtyTimestamp != null) && (!lastDirtyTimestamp.equals(appInfo.getLastDirtyTimestamp()))) {
Object[] args = {id, appInfo.getLastDirtyTimestamp(), lastDirtyTimestamp, isReplication};
//本次续约携带的lastDirtyTimestamp 晚于 实例的LastDirtyTimestamp
if (lastDirtyTimestamp > appInfo.getLastDirtyTimestamp()) {
logger.debug(
"Time to sync, since the last dirty timestamp differs -"
+ " ReplicationInstance id : {},Registry : {} Incoming: {} Replication: {}",
args);
//返回 NOT_FOUND 404,
return Response.status(Status.NOT_FOUND).build();
}
//本次续约携带的lastDirtyTimestamp 早于 实例的lastDirtyTimestamp
else if (appInfo.getLastDirtyTimestamp() > lastDirtyTimestamp) {
// In the case of replication, send the current instance info in the registry for the
// replicating node to sync itself with this one.
//如果是被其他eureka节点同步过来的信息
if (isReplication) {
logger.debug(
"Time to sync, since the last dirty timestamp differs -"
+ " ReplicationInstance id : {},Registry : {} Incoming: {} Replication: {}",
args);
// 返回CONFLICT 409 。 返回了appInfo(该节点的实例的数据信息) 给原本主动同步的eureka节点
return Response.status(Status.CONFLICT).entity(appInfo).build();
} else {
return Response.ok().build();
}
}
}
}
return Response.ok().build();
}
//服务状态变更
@PUT
@Path("status")
public Response statusUpdate(
@QueryParam("value") String newStatus,
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication,
@QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {
try {
//使用服务名称和实例id获取实例
//判断实例是否存在
if (registry.getInstanceByAppAndId(app.getName(), id) == null) {
logger.warn("Instance not found: {}/{}", app.getName(), id);
return Response.status(Status.NOT_FOUND).build();
}
//实例状态更新
boolean isSuccess = registry.statusUpdate(app.getName(), id,
InstanceStatus.valueOf(newStatus), lastDirtyTimestamp,
"true".equals(isReplication));
if (isSuccess) {
logger.info("Status updated: {} - {} - {}", app.getName(), id, newStatus);
return Response.ok().build();
} else {
logger.warn("Unable to update status: {} - {} - {}", app.getName(), id, newStatus);
return Response.serverError().build();
}
} catch (Throwable e) {
logger.error("Error updating instance {} for status {}", id,
newStatus);
return Response.serverError().build();
}
}
//服务剔除
@DELETE
public Response cancelLease(
@HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication) {
try {
boolean isSuccess = registry.cancel(app.getName(), id,
"true".equals(isReplication));
if (isSuccess) {
logger.debug("Found (Cancel): {} - {}", app.getName(), id);
return Response.ok().build();
} else {
logger.info("Not Found (Cancel): {} - {}", app.getName(), id);
return Response.status(Status.NOT_FOUND).build();
}
} catch (Throwable e) {
logger.error("Error (cancel): {} - {}", app.getName(), id, e);
return Response.serverError().build();
}
}
看下同步给其他eureka节点失败的处理(非IoException,ReplicationTaskProcessor会对网络通信异常返回ProcessingResult.Congestion或者ProcessingResult.TransientError,然后重新提交任务到队列中)。
PeerEurekaNode,心跳续约操作还重写了handleFailure做了额外的操作。
public void heartbeat(final String appName, final String id,
final InstanceInfo info, final InstanceStatus overriddenStatus,
boolean primeConnection) throws Throwable {
//省略部分代码
ReplicationTask replicationTask = new InstanceReplicationTask(targetHost, Action.Heartbeat, info, overriddenStatus, false) {
@Override
public EurekaHttpResponse<InstanceInfo> execute() throws Throwable {
return replicationClient.sendHeartBeat(appName, id, info, overriddenStatus);
}
//心跳续约同步到eureka其他节点失败
@Override
public void handleFailure(int statusCode, Object responseEntity) throws Throwable {
super.handleFailure(statusCode, responseEntity);
//如果为404
if (statusCode == 404) {
logger.warn("{}: missing entry.", getTaskName());
if (info != null) {
logger.warn("{}: cannot find instance id {} and hence replicating the instance with status {}",
getTaskName(), info.getId(), info.getStatus());
//向该失败的eureka节点,重新发送客户端注册请求。
register(info);
}
}
//SyncWhenTimestampDiffers默认为true
else if (config.shouldSyncWhenTimestampDiffers()) {
InstanceInfo peerInstanceInfo = (InstanceInfo) responseEntity;
if (peerInstanceInfo != null) {
//使用返回状态码非404的eureka节点发送回来的peerInstanceInfo(实例信息)更新本地的实例数据
syncInstancesIfTimestampDiffers(appName, id, info, peerInstanceInfo);
}
}
}
};
//省略部分代码
}