Eureka Server Request Handling and Instance Registration

When a Eureka client initiates registration via a POST request, it invokes the ApplicationResource.addInstance method. This method performs validation and delegates the registration logic.

@POST
@Consumes({"application/json", "application/xml"})
public Response addInstance(InstanceInfo instanceData,
                            @HeaderParam(PeerEurekaNode.HEADER_REPLICATION) String replicationFlag) {
    
    DataCenterInfo dataCenterInfo = instanceData.getDataCenterInfo();
    if (dataCenterInfo instanceof UniqueIdentifier) {
        String dataCenterId = ((UniqueIdentifier) dataCenterInfo).getId();
        if (isBlank(dataCenterId)) {
            boolean validationEnabled = "true".equalsIgnoreCase(
                serverConfig.getExperimental("registration.validation.dataCenterInfoId"));
            if (validationEnabled) {
                String errorMessage = "DataCenterInfo of type " + dataCenterInfo.getClass() + 
                                      " must contain a valid id";
                return Response.status(400).entity(errorMessage).build();
            } else if (dataCenterInfo instanceof AmazonInfo) {
                AmazonInfo awsInfo = (AmazonInfo) dataCenterInfo;
                String instanceIdentifier = awsInfo.get(AmazonInfo.MetaDataKey.instanceId);
                if (instanceIdentifier == null) {
                    awsInfo.getMetadata().put(AmazonInfo.MetaDataKey.instanceId.getName(), 
                                              instanceData.getId());
                }
            } else {
                logger.warn("Registering DataCenterInfo of type {} without an appropriate id", 
                            dataCenterInfo.getClass());
            }
        }
    }

    registry.register(instanceData, "true".equals(replicationFlag));
    return Response.status(204).build();
}

PeerAwareInstanceRegistryImpl.register Method

The registration request is forwarded to PeerAwareInstanceRegistryImpl.register. This method determines the lease duration and replicates the registration to other nodes in the Eureka cluster.

@Override
public void register(final InstanceInfo instanceData, final boolean isReplication) {
    int leaseTimeout = Lease.DEFAULT_DURATION_IN_SECS;
    if (instanceData.getLeaseInfo() != null && instanceData.getLeaseInfo().getDurationInSecs() > 0) {
        leaseTimeout = instanceData.getLeaseInfo().getDurationInSecs();
    }
    super.register(instanceData, leaseTimeout, isReplication);
    replicateToPeers(Action.Register, instanceData.getAppName(), instanceData.getId(), 
                     instanceData, null, isReplication);
}

AbstractInstanceRegistry.register Method

The core registration logic resides in AbstractInstanceRegistry.register. It stores the instance information in a nested ConcurrentHashMap structure.

public void register(InstanceInfo instanceData, int leaseDuration, boolean isReplication) {
    try {
        read.lock();
        Map<string lease="">> appInstances = registry.get(instanceData.getAppName());
        REGISTER.increment(isReplication);
        if (appInstances == null) {
            ConcurrentHashMap<string lease="">> newAppMap = new ConcurrentHashMap<>();
            appInstances = registry.putIfAbsent(instanceData.getAppName(), newAppMap);
            if (appInstances == null) {
                appInstances = newAppMap;
            }
        }
        Lease<instanceinfo> existingLease = appInstances.get(instanceData.getId());
        if (existingLease != null && (existingLease.getHolder() != null)) {
            Long existingTimestamp = existingLease.getHolder().getLastDirtyTimestamp();
            Long newTimestamp = instanceData.getLastDirtyTimestamp();
            if (existingTimestamp > newTimestamp) {
                instanceData = existingLease.getHolder();
            }
        } else {
            synchronized (lock) {
                if (this.expectedNumberOfClientsSendingRenews > 0) {
                    this.expectedNumberOfClientsSendingRenews = this.expectedNumberOfClientsSendingRenews + 1;
                    updateRenewsPerMinThreshold();
                }
            }
        }
        Lease<instanceinfo> newLease = new Lease<>(instanceData, leaseDuration);
        if (existingLease != null) {
            newLease.setServiceUpTimestamp(existingLease.getServiceUpTimestamp());
        }
        appInstances.put(instanceData.getId(), newLease);
        recentRegisteredQueue.add(new Pair<>(
            System.currentTimeMillis(),
            instanceData.getAppName() + "(" + instanceData.getId() + ")"));
        if (!InstanceStatus.UNKNOWN.equals(instanceData.getOverriddenStatus())) {
            if (!overriddenInstanceStatusMap.containsKey(instanceData.getId())) {
                overriddenInstanceStatusMap.put(instanceData.getId(), instanceData.getOverriddenStatus());
            }
        }
        InstanceStatus overriddenStatusFromMap = overriddenInstanceStatusMap.get(instanceData.getId());
        if (overriddenStatusFromMap != null) {
            instanceData.setOverriddenStatus(overriddenStatusFromMap);
        }
        InstanceStatus determinedStatus = getOverriddenInstanceStatus(instanceData, existingLease, isReplication);
        instanceData.setStatusWithoutDirty(determinedStatus);
        if (InstanceStatus.UP.equals(instanceData.getStatus())) {
            newLease.serviceUp();
        }
        instanceData.setActionType(ActionType.ADDED);
        recentlyChangedQueue.add(new RecentlyChangedItem(newLease));
        instanceData.setLastUpdatedTimestamp();
        invalidateCache(instanceData.getAppName(), instanceData.getVIPAddress(), 
                        instanceData.getSecureVipAddress());
    } finally {
        read.unlock();
    }
}</instanceinfo></instanceinfo></string></string>

The server stores instance data in a two-level map: the outer key is the applicasion name, and the enner key is the instance ID. Each instance is wrapped in a Lease object that manages its lifecycle, including a default 90-second expiration. The registration process also handles lease renewal timestamps, status overrides, and cache invalidation to ensure consistent state across the server.

Tags: Eureka ServiceRegistry microservices java NetflixOSS

Posted on Thu, 01 Oct 2026 16:39:22 +0000 by saltwater