sequence

This paper mainly studies instanceEnabledOnit attribute of Spring Cloud Eureka

EurekaInstanceConfigBean

Spring – the cloud – netflix – eureka – the client – 2.0.0. RC1 – sources. The jar! /org/springframework/cloud/netflix/eureka/EurekaInstanceConfigBean.java

@ConfigurationProperties("eureka.instance")
public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware {
	//......
	/**
	 * Indicates whether the instance should be enabled for taking traffic as soon as it
	 * is registered with eureka. Sometimes the application might need to dosome * pre-processing before it is ready to take traffic. */ private boolean instanceEnabledOnit; / /... }Copy the code

This property is used to determine whether the application service can start receiving requests as soon as it is registered

The configuration definition is as follows: spring-cloud-Netflix-Eureka-client-2.0.0rc1.jar! /META-INF/spring-configuration-metadata.json

    {
      "sourceType": "org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean"."defaultValue": false."name": "eureka.instance.instance-enabled-onit"."description": "Indicates whether the instance should be enabled for taking traffic as soon as it\n is registered with eureka. Sometimes the application might need to do some\n pre-processing before it is ready to take traffic."."type": "java.lang.Boolean"
    }
Copy the code

PropertiesInstanceConfig

Eureka – the client – 1.8.8 – sources jar! /com/netflix/appinfo/PropertiesInstanceConfig.java

	static final String TRAFFIC_ENABLED_ON_INIT_KEY = "traffic.enabled";

    @Override
    public boolean isInstanceEnabledOnit() {
        return configInstance.getBooleanProperty(namespace + TRAFFIC_ENABLED_ON_INIT_KEY,
                super.isInstanceEnabledOnit()).get();
    }
Copy the code

Here is a super isInstanceEnabledOnit ()

Change to STARTING

InstanceInfoFactory

Spring – the cloud – netflix – eureka – the client – 2.0.0. RC1 – sources. The jar! /org/springframework/cloud/netflix/eureka/InstanceInfoFactory.java

public class InstanceInfoFactory {

	private static final Log log = LogFactory.getLog(InstanceInfoFactory.class);

	public InstanceInfo create(EurekaInstanceConfig config) {
		LeaseInfo.Builder leaseInfoBuilder = LeaseInfo.Builder.newBuilder()
				.setRenewalIntervalInSecs(config.getLeaseRenewalIntervalInSeconds())
				.setDurationInSecs(config.getLeaseExpirationDurationInSeconds());

		// Builder the instance information to be registered with eureka
		// server
		InstanceInfo.Builder builder = InstanceInfo.Builder.newBuilder();

		String namespace = config.getNamespace();
		if(! namespace.endsWith(".")) {
			namespace = namespace + ".";
		}
		builder.setNamespace(namespace).setAppName(config.getAppname())
				.setInstanceId(config.getInstanceId())
				.setAppGroupName(config.getAppGroupName())
				.setDataCenterInfo(config.getDataCenterInfo())
				.setIPAddr(config.getIpAddress()).setHostName(config.getHostName(false))
				.setPort(config.getNonSecurePort())
				.enablePort(InstanceInfo.PortType.UNSECURE,
						config.isNonSecurePortEnabled())
				.setSecurePort(config.getSecurePort())
				.enablePort(InstanceInfo.PortType.SECURE, config.getSecurePortEnabled())
				.setVIPAddress(config.getVirtualHostName())
				.setSecureVIPAddress(config.getSecureVirtualHostName())
				.setHomePageUrl(config.getHomePageUrlPath(), config.getHomePageUrl())
				.setStatusPageUrl(config.getStatusPageUrlPath(),
						config.getStatusPageUrl())
				.setHealthCheckUrls(config.getHealthCheckUrlPath(),
						config.getHealthCheckUrl(), config.getSecureHealthCheckUrl())
				.setASGName(config.getASGName());

		// Start off with the STARTING state to avoid traffic
		if(! config.isInstanceEnabledOnit()) { InstanceInfo.InstanceStatus initialStatus = InstanceInfo.InstanceStatus.STARTING;if (log.isInfoEnabled()) {
				log.info("Setting initial instance status as: " + initialStatus);
			}
			builder.setStatus(initialStatus);
		}
		else {
			if (log.isInfoEnabled()) {
				log.info("Setting initial instance status as: "
						+ InstanceInfo.InstanceStatus.UP
						+ ". This may be too early for the instance to advertise itself as available. "
						+ "You would instead want to control this via a healthcheck handler.");
			}
		}

		// Add any user-specific metadata information
		for (Map.Entry<String, String> mapEntry : config.getMetadataMap().entrySet()) {
			String key = mapEntry.getKey();
			String value = mapEntry.getValue();
			// only add the metadata if the value is present
			if(value ! = null && ! value.isEmpty()) { builder.add(key, value); } } InstanceInfo instanceInfo = builder.build(); instanceInfo.setLeaseInfo(leaseInfoBuilder.build());returninstanceInfo; }}Copy the code

Judge isInstanceEnabledOnit can see here, if not, the InstanceStatus initial state for the InstanceInfo. InstanceStatus. STARTING; When InstanceInfo is created, status is initialized to InstanceStatus.UP by default, so if true, log here

EurekaRegistration

Spring – the cloud – netflix – eureka – the client – 2.0.0. RC1 – sources. The jar! /org/springframework/cloud/netflix/eureka/serviceregistry/EurekaRegistration.java

		public EurekaRegistration build() {
			Assert.notNull(instanceConfig, "instanceConfig may not be null");

			if (this.applicationInfoManager == null) {
				InstanceInfo instanceInfo = new InstanceInfoFactory().create(this.instanceConfig);
				this.applicationInfoManager = new ApplicationInfoManager(this.instanceConfig, instanceInfo);
			}
			if (this.eurekaClient == null) {
				Assert.notNull(this.clientConfig, "if eurekaClient is null, EurekaClientConfig may not be null");
				Assert.notNull(this.publisher, "if eurekaClient is null, ApplicationEventPublisher may not be null");

				this.eurekaClient = new CloudEurekaClient(this.applicationInfoManager, this.clientConfig, this.publisher);
			}
			return new EurekaRegistration(instanceConfig, eurekaClient, applicationInfoManager, healthCheckHandler);
		}
Copy the code

EurekaRegistration creates InstanceInfo using new InstanceInfoFactory().create(this.instanceconfig)

DiscoveryClient.initScheduledTasks

Eureka – the client – 1.8.8 – sources jar! /com/netflix/discovery/DiscoveryClient.java

private void initScheduledTasks() {
        if (clientConfig.shouldFetchRegistry()) {
            // registry cache refresh timer
            int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
            int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
            scheduler.schedule(
                    new TimedSupervisorTask(
                            "cacheRefresh",
                            scheduler,
                            cacheRefreshExecutor,
                            registryFetchIntervalSeconds,
                            TimeUnit.SECONDS,
                            expBackOffBound,
                            new CacheRefreshThread()
                    ),
                    registryFetchIntervalSeconds, TimeUnit.SECONDS);
        }

        if (clientConfig.shouldRegisterWithEureka()) {
            int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
            int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
            logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs);

            // Heartbeat timer
            scheduler.schedule(
                    new TimedSupervisorTask(
                            "heartbeat",
                            scheduler,
                            heartbeatExecutor,
                            renewalIntervalInSecs,
                            TimeUnit.SECONDS,
                            expBackOffBound,
                            new HeartbeatThread()
                    ),
                    renewalIntervalInSecs, TimeUnit.SECONDS);

            // InstanceInfo replicator
            instanceInfoReplicator = new InstanceInfoReplicator(
                    this,
                    instanceInfo,
                    clientConfig.getInstanceInfoReplicationIntervalSeconds(),
                    2); // burstSize

            statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
                @Override
                public String getId() {
                    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(); }};if (clientConfig.shouldOnDemandUpdateStatusChange()) {
                applicationInfoManager.registerStatusChangeListener(statusChangeListener);
            }

            instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
        } else {
            logger.info("Not registering with Eureka server per configuration"); }}Copy the code

The client constructor initializes initScheduledTasks, It calls the instanceInfoReplicator. Start (clientConfig getInitialInstanceInfoReplicationIntervalSeconds ()), the default is delayed for 40 seconds

InstanceInfoReplicator

Eureka – the client – 1.8.8 – sources jar! /com/netflix/discovery/InstanceInfoReplicator.java

class InstanceInfoReplicator implements Runnable {
	
	public void start(int initialDelayMs) {
        if (started.compareAndSet(false.true)) {
            instanceInfo.setIsDirty();  // for initial register
            Future next = scheduler.schedule(this, initialDelayMs, TimeUnit.SECONDS);
            scheduledPeriodicRef.set(next);
        }
    }

    public void run() {
        try {
            discoveryClient.refreshInstanceInfo();

            Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
            if(dirtyTimestamp ! = null) { discoveryClient.register(); instanceInfo.unsetIsDirty(dirtyTimestamp); } } catch (Throwable t) { logger.warn("There was a problem with the instance info replicator", t);
        } finally {
            Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);
            scheduledPeriodicRef.set(next);
        }
    }

    public boolean onDemandUpdate() {
        if (rateLimiter.acquire(burstSize, allowedRatePerMinute)) {
            if(! scheduler.isShutdown()) { scheduler.submit(newRunnable() {
                    @Override
                    public void run() {
                        logger.debug("Executing on-demand update of local InstanceInfo");
    
                        Future latestPeriodic = scheduledPeriodicRef.get();
                        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); } InstanceInfoReplicator.this.run(); }});return true;
            } else {
                logger.warn("Ignoring onDemand update due to stopped scheduler");
                return false; }}else {
            logger.warn("Ignoring onDemand update due to rate limiter");
            return false; }}}Copy the code

This is set to dirty initially, and then the first time it is executed, register is triggered, which calls registration remotely. DiscoveryClient has a statusChangeListener, which calls the onDemandUpdate method here, and the onDemandUpdate method executes the run method within the frequency limit.

Change to the UP

EurekaAutoServiceRegistration

Spring – the cloud – netflix – eureka – the client – 2.0.0. RC1 – sources. The jar! /org/springframework/cloud/netflix/eureka/serviceregistry/EurekaAutoServiceRegistration.java

public class EurekaAutoServiceRegistration implements AutoServiceRegistration, SmartLifecycle, Ordered {
	//......
	public void start() {
		// only set the port ifthe nonSecurePort or securePort is 0 and this.port ! = 0if(this.port.get() ! = 0) {if (this.registration.getNonSecurePort() == 0) {
				this.registration.setNonSecurePort(this.port.get());
			}

			if (this.registration.getSecurePort() == 0 && this.registration.isSecure()) {
				this.registration.setSecurePort(this.port.get());
			}
		}

		// only initialize if nonSecurePort is greater than 0 and it isn't already running // because of containerPortInitializer below if (! this.running.get() && this.registration.getNonSecurePort() > 0) { this.serviceRegistry.register(this.registration); this.context.publishEvent( new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig())); this.running.set(true); }}}Copy the code

Here is automatic registration, serviceregistry.register (this.registration)

	public void register(EurekaRegistration reg) {
		maybeInitializeClient(reg);

		if (log.isInfoEnabled()) {
			log.info("Registering application " + reg.getInstanceConfig().getAppname()
					+ " with eureka with status "
					+ reg.getInstanceConfig().getInitialStatus());
		}

		reg.getApplicationInfoManager()
				.setInstanceStatus(reg.getInstanceConfig().getInitialStatus());

		reg.getHealthCheckHandler().ifAvailable(healthCheckHandler ->
				reg.getEurekaClient().registerHealthCheck(healthCheckHandler));
	}
Copy the code

This changes the status to reg.getInstanceconfig ().getInitialStatus(), which defaults to UP

Spring – the cloud – netflix – eureka – the client – 2.0.0. RC1 – sources. The jar! /org/springframework/cloud/netflix/eureka/EurekaInstanceConfigBean.java

	/**
	 * Initial status to register with rmeote Eureka server.
	 */
	private InstanceStatus initialStatus = InstanceStatus.UP;
Copy the code

summary

During application startup, you can set the status of the eureka server initially registered with the Eureka server to UP or STARTING based on the eureka.instance.instance-enabled-onit configuration (default: false). The default value is “STARTING”, and then changed to “UP” during automatic registration, indicating that requests can be received.

  • DiscoveryClient initialses a number of scheduled tasks, including InstanceInfoReplicator’s run method, which is delayed by 40 seconds by default. It starts with instanceInfo.setisdirty (). The first execution then triggers DiscoveryClient.register ().
  • And EurekaAutoServiceRegistration at startup, invokes the serviceRegistry. Register (enclosing registration), after the status, issue StatusChangeEvent, DiscoveryClient has a statusChangeListener that invokes InstanceInfoReplicator’s onDemandUpdate method. When the onDemandUpdate method does not exceed the frequency limit, The InstanceInfoReplicator run method is executed.

Can be found either InstanceInfoReplicator delay task, or urekaAutoServiceRegistration StatusChangeEvent change, Finally, InstanceInfoReplicator’s run method triggers DiscoveryClient.register () to register the remote Eureka server.