Client configuration updated

The initialization task

When DiscoveryClient is initialized, the method initScheduledTasks() is called with the following code in the method

// InstanceInfo replicator Creates the InstanceInfo replicator
InstanceInfoReplicator implements the Runnable interface
instanceInfoReplicator = new InstanceInfoReplicator(
  this,
  instanceInfo,
  clientConfig.getInstanceInfoReplicationIntervalSeconds(),
  / / critical point
  2); // burstSize
// State change listener
statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
  @Override
  public String getId(a) {
    return "statusChangeListener";
  }
  @Override
  public void notify(StatusChangeEvent statusChangeEvent) {
    if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||
        InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {
      // log at warn level if DOWN was involved
      logger.warn("Saw local status change event {}", statusChangeEvent);
    } else {
      logger.info("Saw local status change event {}", statusChangeEvent); } instanceInfoReplicator.onDemandUpdate(); }};// Whether to update as needed. Default is true
if (clientConfig.shouldOnDemandUpdateStatusChange()) {
  // Register the listener
  applicationInfoManager.registerStatusChangeListener(statusChangeListener);
}
/ / start
instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
Copy the code

Instanceinforelocator #start(

Task scheduling

It should be noted that scheduling is done once, and will be rescheduled in finally method after scheduling is completed

public void start(int initialDelayMs) {
  if (started.compareAndSet(false.true)) {
    instanceInfo.setIsDirty();  // for initial register
    // Start scheduling by running the run method in InstanceInfoReplicator
    Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS); scheduledPeriodicRef.set(next); }}public void run(a) {
  try {
    // Refresh instance information
    discoveryClient.refreshInstanceInfo();
    Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
    // If the client's local cache is dirty, register it and make it non-dirty
    if(dirtyTimestamp ! =null) { discoveryClient.register(); instanceInfo.unsetIsDirty(dirtyTimestamp); }}catch (Throwable t) {
  } finally {
    // Start scheduling
    Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS); scheduledPeriodicRef.set(next); }}Copy the code

Example Refresh local instance information

// Refresh the locally cached instanceInfo
void refreshInstanceInfo(a) {
  // The following two ways to refresh information are to update the local instanceInfo, set it to dirty and update the last dirty timestamp
  // Verify that the hostname has changed. If it does, the DataCenterInfo will be passed to EurekaServer in the next heartbeat
  applicationInfoManager.refreshDataCenterInfoIfRequired();
  // Refresh the lease information. The client can change the heartbeat interval and instance expulsion time (how long has the server not received the heartbeat and removed the instance).
  applicationInfoManager.refreshLeaseInfoIfRequired();
  InstanceStatus status;
  try {
    status = getHealthCheckHandler().getStatus(instanceInfo.getStatus());
  } catch (Exception e) {
    logger.warn("Exception from healthcheckHandler.getStatus, setting status to DOWN", e);
    status = InstanceStatus.DOWN;
  }
  if (null! = status) {// State change processingapplicationInfoManager.setInstanceStatus(status); }}Copy the code

Listening for state changes

/ / current limiter
private final RateLimiter rateLimiter;
// The burst point is fixed at 2
private final int burstSize;
// The frequency of instance changes per minute is allowed
private final int allowedRatePerMinute;
​
InstanceInfoReplicator(。。。。){
  / / replicationIntervalSeconds () can be configured according to the incoming values default is 30 s
  // This works out to 4 changes per minute
  this.allowedRatePerMinute = 60 * this.burstSize / this.replicationIntervalSeconds;
}
​
public boolean onDemandUpdate(a) {
  // If the frequency limit is not exceeded
  if (rateLimiter.acquire(burstSize, allowedRatePerMinute)) {
    // The current scheduling task is not closed
    if(! scheduler.isShutdown()) {// Submit a new task task
      scheduler.submit(new Runnable() {
        @Override
        public void run(a) {
          logger.debug("Executing on-demand update of local InstanceInfo");
          // This is set to scheduledPeriodicRef(which is set to the current scheduling task)
          Future latestPeriodic = scheduledPeriodicRef.get();
          // If it is not empty and the task is incomplete, cancel it
          if(latestPeriodic ! =null && !latestPeriodic.isDone()) {
            logger.debug("Canceling the latest scheduled update, it will be rescheduled at the end of on demand update");
            latestPeriodic.cancel(false);
          }
          // Call the run method for a new round of scheduling
          InstanceInfoReplicator.this.run(); }});return true;
    } else {
      return false; }}else {
    return false; }}Copy the code

conclusion

  1. The client Instance configuration is updated, and the InstanceInfo replicator periodically synchronizes the client Instance changes to the EurekaServer
  2. More frequency is limited by the use of RateLimiter
  3. InstanceInfoReplicator tasks for instance changes and state changes are InstanceInfoReplicator tasks for scheduling details