The foreword 0.

  • Springboot version: 2.1.9.RELEASE
  • Springcloud version: Greenwich.SR4

1. Process the deletion request

The server handles client state change and state deletion requests in the InstanceResource class

// InstanceResource.class
public Response deleteStatusUpdate(
        @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication,
        @QueryParam("value") String newStatusValue,
        @QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {
    // isReplication: indicates whether synchronous replication is performed by cluster nodes
    // newStatusValue: null when the client initiates the deletion state
    // lastDirtyTimestamp: last modified timestamp (dirty)
    try {
        if (registry.getInstanceByAppAndId(app.getName(), id) == null) {
            // Query the service instance information in the local registry. If no service instance information is found, 404 is returned
            logger.warn("Instance not found: {}/{}", app.getName(), id);
            return Response.status(Status.NOT_FOUND).build();
        }

        // newStatusValue = null, so newStatus = UNKNOWN
        InstanceStatus newStatus = newStatusValue == null ? InstanceStatus.UNKNOWN : InstanceStatus.valueOf(newStatusValue);
        // 2 Handle deletion status
        boolean isSuccess = registry.deleteStatusOverride(app.getName(), id,
                newStatus, lastDirtyTimestamp, "true".equals(isReplication));

        if (isSuccess) {
            logger.info("Status override removed: {} - {}", app.getName(), id);
            // 200 is returned on success
            return Response.ok().build();
        } else {
            // Failure to process returns 500
            logger.warn("Unable to remove status override: {} - {}", app.getName(), id);
            returnResponse.serverError().build(); }}catch (Throwable e) {
        logger.error("Error removing instance's {} status override", id);
        // Handle an exception and return 500
        returnResponse.serverError().build(); }}Copy the code

2. Handle the deletion status

// PeerAwareInstanceRegistryImpl.class
public boolean deleteStatusOverride(String appName, String id,
                                    InstanceStatus newStatus,
                                    String lastDirtyTimestamp,
                                    boolean isReplication) {
    // 3 Call the parent class to handle the delete state method
    if (super.deleteStatusOverride(appName, id, newStatus, lastDirtyTimestamp, isReplication)) {
        // 4 Synchronize the data to the cluster node
        replicateToPeers(Action.DeleteStatusOverride, appName, id, null.null, isReplication);
        return true;
    }
    return false;
}
Copy the code

3. The parent class handles the delete state method

// AbstractInstanceRegistry.class
public boolean deleteStatusOverride(String appName, String id,
                                    InstanceStatus newStatus,
                                    String lastDirtyTimestamp,
                                    boolean isReplication) {
    try {
        // Open the read lock
        read.lock();
        STATUS_OVERRIDE_DELETE.increment(isReplication);
        // Get service lease information
        Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
        Lease<InstanceInfo> lease = null;
        if(gMap ! =null) {
            // Get instance lease information
            lease = gMap.get(id);
        }
        if (lease == null) {
            // If not, return false
            return false;
        } else {
            // Refresh the lease expiration time
            // The client is still alive, so update the lease expiration time
            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);
            }

            / / to get cover state, and deleted from the overriddenInstanceStatusMap
            InstanceStatus currentOverride = overriddenInstanceStatusMap.remove(id);
            if(currentOverride ! =null&& info ! =null) {
                // Set the coverage state of the instance information to UNKNOWN
                info.setOverriddenStatus(InstanceStatus.UNKNOWN);
                // Sets the state of the instance information, but does not mark dirty
                info.setStatusWithoutDirty(newStatus);
                long replicaDirtyTimestamp = 0;
                if(lastDirtyTimestamp ! =null) {
                    replicaDirtyTimestamp = Long.valueOf(lastDirtyTimestamp);
                }
                // If the replication's dirty timestamp is more than the existing one, just update
                // it to the replica's.
                if (replicaDirtyTimestamp > info.getLastDirtyTimestamp()) {
                    // If the latest modified timestamp of the client instance is larger than the latest modified timestamp of the corresponding instance information in the local registry (dirty)
                    // Update the local to the client
                    info.setLastDirtyTimestamp(replicaDirtyTimestamp);
                }
                // Set the behavior type to change
                info.setActionType(ActionType.MODIFIED);
                // The instance change lease information is put into the latest change queue
                recentlyChangedQueue.add(new RecentlyChangedItem(lease));
                // Set the latest modified timestamp of the local instance information
                info.setLastUpdatedTimestamp();
                // invalidate the corresponding cache
                invalidateCache(appName, info.getVIPAddress(), info.getSecureVipAddress());
            }
            return true; }}finally{close read lock read.unlock(); }}Copy the code

4. Synchronize the data to the cluster node

This is covered in EurekaServer- handling client registration requests

5. Process status change requests

// InstanceResource.class
public Response statusUpdate(
        @QueryParam("value") String newStatus,
        @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String isReplication,
        @QueryParam("lastDirtyTimestamp") String lastDirtyTimestamp) {
    try {
        if (registry.getInstanceByAppAndId(app.getName(), id) == null) {
            logger.warn("Instance not found: {}/{}", app.getName(), id);
            // Query instance information in the local registry. If no instance is found, 404 is returned
            return Response.status(Status.NOT_FOUND).build();
        }
        // 6 Handle the change status
        boolean isSuccess = registry.statusUpdate(app.getName(), id,
                InstanceStatus.valueOf(newStatus), lastDirtyTimestamp,
                "true".equals(isReplication));

        if (isSuccess) {
            logger.info("Status updated: {} - {} - {}", app.getName(), id, newStatus);
            // 200 is returned on success
            return Response.ok().build();
        } else {
            logger.warn("Unable to update status: {} - {} - {}", app.getName(), id, newStatus);
            // Return 500 on success
            returnResponse.serverError().build(); }}catch (Throwable e) {
        logger.error("Error updating instance {} for status {}", id,
                newStatus);
        // Handle an exception and return 500
        returnResponse.serverError().build(); }}Copy the code

6. Handle the change status

// PeerAwareInstanceRegistryImpl.class
public boolean statusUpdate(final String appName, final String id,
                            final InstanceStatus newStatus, String lastDirtyTimestamp,
                            final boolean isReplication) {
    // 7 calls the parent class to handle the change status method
    if (super.statusUpdate(appName, id, newStatus, lastDirtyTimestamp, isReplication)) {
        // 4 Synchronize the data to the cluster node
        replicateToPeers(Action.StatusUpdate, appName, id, null, newStatus, isReplication);
        return true;
    }
    return false;
}
Copy the code

7. The parent class handles change-state methods

// AbstractInstanceRegistry.class
public boolean statusUpdate(String appName, String id,
                            InstanceStatus newStatus, String lastDirtyTimestamp,
                            boolean isReplication) {
    try {
        // Open the read lock
        read.lock();
        STATUS_UPDATE.increment(isReplication);
        // Get service lease information
        Map<String, Lease<InstanceInfo>> gMap = registry.get(appName);
        Lease<InstanceInfo> lease = null;
        if(gMap ! =null) {
            // Get instance lease information
            lease = gMap.get(id);
        }
        if (lease == null) {
            return false;
        } else {
            // Refresh the lease expiration time
            // Update the lease expiration time because the client is still alive
            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))) {
                // If the local instance information is not empty and the status is inconsistent with that requested by the client
                // Mark service as UP if needed
                if (InstanceStatus.UP.equals(newStatus)) {
                    // If the state is to change to UP and the instance is started for the first time, the startup time is recorded
                    lease.serviceUp();
                }
                // This is NAC overriden status
                / / to overriddenInstanceStatusMap saving changes
                overriddenInstanceStatusMap.put(id, newStatus);
                // Set it for transfer of overridden status to replica on
                // replica start up
                // Instance info Sets the overwrite status
                info.setOverriddenStatus(newStatus);
                long replicaDirtyTimestamp = 0;
                // Sets the state of the instance information, but does not record the dirty timestamp
                info.setStatusWithoutDirty(newStatus);
                if(lastDirtyTimestamp ! =null) {
                    replicaDirtyTimestamp = Long.valueOf(lastDirtyTimestamp);
                }
                // If the replication's dirty timestamp is more than the existing one, just update
                // it to the replica's.
                if (replicaDirtyTimestamp > info.getLastDirtyTimestamp()) {
                    // If the latest modified timestamp of the client instance is larger than the latest modified timestamp of the corresponding instance information in the local registry (dirty)
                    // Update the local to the client
                    info.setLastDirtyTimestamp(replicaDirtyTimestamp);
                }
                // Set the behavior type to change
                info.setActionType(ActionType.MODIFIED);
                // Put into the latest change queue
                recentlyChangedQueue.add(new RecentlyChangedItem(lease));
                // Set the latest modified timestamp of the local instance information
                info.setLastUpdatedTimestamp();
                // invalidate the corresponding cache
                invalidateCache(appName, info.getVIPAddress(), info.getSecureVipAddress());
            }
            return true; }}finally {
        // Close the read lockread.unlock(); }}Copy the code