Eureka client of SpringCloud source code study notes-service renewal

1. Service renewal entrance

  In "Eureka Client-Initialization" , we know that in the initScheduledTasks() method in the constructor of the DiscoveryClient object, the service renewal is realized. The specific implementation is as follows:

 // 创建心跳服务线程,同时进行服务续约
 heartbeatTask = new TimedSupervisorTask(
          new HeartbeatThread()
          renewalIntervalInSecs, TimeUnit.SECONDS);

  In the above method, a TimedSupervisorTask task is created first, and the task actually executed is realized by HeartbeatThread, and then the scheduler.schedule() method is called to execute the contract renewal task regularly.

2, TimedSupervisorTask class TimerTask

  In fact, the logic of service renewal is similar to service discovery, but when learning about service renewal, I didn't have a deep understanding of the TimedSupervisorTask class. Let's learn about this class first. The TimedSupervisorTask class inherits the TimerTask class, so when the scheduler executes the schedule() method, the run() method of the TimedSupervisorTask object will be executed. This class is mainly used to supervise the execution of subtasks, that is, the tasks of the HeartbeatThread object, while enhancing timeout processing and thread safety.

2.1, the constructor
public TimedSupervisorTask(String name, ScheduledExecutorService scheduler, ThreadPoolExecutor executor,int timeout, TimeUnit timeUnit, int expBackOffBound, Runnable task) {
    //线程名称           = name;
    this.scheduler = scheduler;
    this.executor = executor;
    this.timeoutMillis = timeUnit.toMillis(timeout);
    this.task = task;
    this.delay = new AtomicLong(timeoutMillis);
    this.maxDelay = timeoutMillis * expBackOffBound;

    // 心跳结果的计数器
    successCounter = Monitors.newCounter("success");
    timeoutCounter = Monitors.newCounter("timeouts");
    rejectedCounter = Monitors.newCounter("rejectedExecutions");
    throwableCounter = Monitors.newCounter("throwables");
    threadPoolLevelGauge = new LongGauge(MonitorConfig.builder("threadPoolUsed").build());
    Monitors.registerObject(name, this);
2.2, run() method
public void run() {
    Future<?> future = null;
    try {
        future = executor.submit(task);
        threadPoolLevelGauge.set((long) executor.getActiveCount());
        future.get(timeoutMillis, TimeUnit.MILLISECONDS);  // block until done or timeout
        threadPoolLevelGauge.set((long) executor.getActiveCount());
	//省略各类续约结构的计数和日志 逻辑 ……
	 finally {
        if (future != null) {

        if (!scheduler.isShutdown()) {
            scheduler.schedule(this, delay.get(), TimeUnit.MILLISECONDS);


  Through the previous study, we know that the HeartbeatThread class is the core logic for heartbeat or contract renewal. This class is an internal class defined in the DiscoveryClient class. This class is also an implementation class of the Runnable interface, so when it is executed, the run() method will be called. The specific implementation is as follows:

private class HeartbeatThread implements Runnable {

     public void run() {
         if (renew()) {
             lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();

  Through the definition of the HeartbeatThread class, we can know that in the run() method, the renew() method of the DiscoveryClient class is first called to renew the contract, and then if the renewal is successful, the value of the lastSuccessfulHeartbeatTimestamp variable will be modified, that is, the current The time is the time when the last contract renewal was successful.

4. The renew() method of the DiscoveryClient class

  In this method, similar to service registration, heartbeat data is sent by calling the sendHeartBeat() method of the AbstractJerseyEurekaHttpClient class, and then the next step is processed according to the returned result. If the heartbeat renewal returns to the NOT_FOUND state, call the register() method to renew the contract. The specific implementation is as follows:

boolean renew() {
    EurekaHttpResponse<InstanceInfo> httpResponse;
    try {
        httpResponse = eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
        logger.debug(PREFIX + "{} - Heartbeat status: {}", appPathIdentifier, httpResponse.getStatusCode());
        if (httpResponse.getStatusCode() == Status.NOT_FOUND.getStatusCode()) {
   + "{} - Re-registering apps/{}", appPathIdentifier, instanceInfo.getAppName());
            long timestamp = instanceInfo.setIsDirtyWithTime();
            boolean success = register();
            if (success) {
            return success;
        return httpResponse.getStatusCode() == Status.OK.getStatusCode();
    } catch (Throwable e) {
        logger.error(PREFIX + "{} - was unable to send heartbeat!", appPathIdentifier, e);
        return false;

5. The sendHeartBeat() method of the AbstractJerseyEurekaHttpClient class

  Similar to the register() method of the AbstractJerseyEurekaHttpClient class, an http request is still sent.

public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info, InstanceStatus overriddenStatus) {
   String urlPath = "apps/" + appName + '/' + id;
   ClientResponse response = null;
   try {
       WebResource webResource = jerseyClient.resource(serviceUrl)
               .queryParam("status", info.getStatus().toString())
               .queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString());
       if (overriddenStatus != null) {
           webResource = webResource.queryParam("overriddenstatus",;
       Builder requestBuilder = webResource.getRequestBuilder();
       response = requestBuilder.put(ClientResponse.class);
       EurekaHttpResponseBuilder<InstanceInfo> eurekaResponseBuilder = anEurekaHttpResponse(response.getStatus(), InstanceInfo.class).headers(headersOf(response));
       if (response.hasEntity() &&
               !HTML.equals(response.getType().getSubtype())) {
     //don't try and deserialize random html errors from the server
   } finally {
       if (logger.isDebugEnabled()) {
           logger.debug("Jersey HTTP PUT {}/{}; statusCode={}", serviceUrl, urlPath, response == null ? "N/A" : response.getStatus());
       if (response != null) {

Guess you like