All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tencent.polaris.plugins.circuitbreaker.composite.HealthCheckContainer Maven / Gradle / Ivy

/*
 * Tencent is pleased to support the open source community by making Polaris available.
 *
 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
 *
 * Licensed under the BSD 3-Clause License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://opensource.org/licenses/BSD-3-Clause
 *
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.tencent.polaris.plugins.circuitbreaker.composite;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import com.tencent.polaris.api.plugin.circuitbreaker.entity.InstanceResource;
import com.tencent.polaris.api.plugin.circuitbreaker.entity.Resource;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.api.utils.CollectionUtils;
import com.tencent.polaris.client.pojo.Node;
import com.tencent.polaris.logging.LoggerFactory;
import com.tencent.polaris.plugins.circuitbreaker.composite.utils.HealthCheckUtils;
import com.tencent.polaris.specification.api.v1.fault.tolerance.FaultDetectorProto;
import org.slf4j.Logger;

import static com.tencent.polaris.logging.LoggingConsts.LOGGING_HEALTHCHECK_EVENT;

public class HealthCheckContainer implements HealthCheckInstanceProvider {

	private static final Logger HC_EVENT_LOG = LoggerFactory.getLogger(LOGGING_HEALTHCHECK_EVENT);

	private static final Logger LOG = LoggerFactory.getLogger(HealthCheckContainer.class);

	private final ServiceKey serviceKey;

	private final Object updateLock = new Object();

	// key is ruleId, value is checker
	private final List healthCheckers = new ArrayList<>();

	private final Map instances = new ConcurrentHashMap<>();

	private final long expireIntervalMilli;

	private final ScheduledFuture future;

	public HealthCheckContainer(ServiceKey serviceKey,
			List faultDetectRules, PolarisCircuitBreaker polarisCircuitBreaker) {
		long checkPeriod = polarisCircuitBreaker.getCheckPeriod();
		expireIntervalMilli = polarisCircuitBreaker.getHealthCheckInstanceExpireInterval();
		this.serviceKey = serviceKey;
		LOG.info("schedule expire task: service {}, interval {}", serviceKey, checkPeriod);
		future = polarisCircuitBreaker.getHealthCheckExecutors().scheduleWithFixedDelay(new Runnable() {
			@Override
			public void run() {
				cleanInstances();
			}
		}, checkPeriod, checkPeriod, TimeUnit.MILLISECONDS);
		if (CollectionUtils.isNotEmpty(faultDetectRules)) {
			for (FaultDetectorProto.FaultDetectRule faultDetectRule : faultDetectRules) {
				ResourceHealthChecker resourceHealthChecker = new ResourceHealthChecker(faultDetectRule, this, polarisCircuitBreaker);
				resourceHealthChecker.start();
				healthCheckers.add(resourceHealthChecker);
			}
		}
	}

	public void addInstance(InstanceResource instanceResource) {
		ResourceHealthChecker.ProtocolInstance instance = instances.computeIfAbsent(instanceResource.getNode(), new Function() {
			@Override
			public ResourceHealthChecker.ProtocolInstance apply(Node node) {
				HC_EVENT_LOG.info("add fault detect instance {}, service {}", instanceResource.getNode(), serviceKey);
				return new ResourceHealthChecker.ProtocolInstance(HealthCheckUtils.parseProtocol(instanceResource.getProtocol()),
						instanceResource);
			}
		});
		instance.doReport();
	}

	@Override
	public Map getInstances() {
		return Collections.unmodifiableMap(instances);
	}

	public Collection getHealthCheckerValues() {
		return Collections.unmodifiableCollection(healthCheckers);
	}

	public void cleanInstances() {
		long curTimeMilli = System.currentTimeMillis();
		for (Map.Entry entry : instances.entrySet()) {
			ResourceHealthChecker.ProtocolInstance protocolInstance = entry.getValue();
			long lastReportMilli = protocolInstance.getLastReportMilli();
			Node node = entry.getKey();
			if (!protocolInstance.isCheckSuccess() && curTimeMilli - lastReportMilli >= expireIntervalMilli) {
				instances.remove(node);
				HC_EVENT_LOG
						.info("clean instance from health check tasks, service {}, expired node {}, lastReportMilli {}",
								serviceKey, node, lastReportMilli);
			}
		}
	}

	public void stop() {
		LOG.info("health check container for service {} has stopped", serviceKey);
		synchronized (updateLock) {
			for (ResourceHealthChecker resourceHealthChecker : healthCheckers) {
				resourceHealthChecker.stop();
			}
		}
		future.cancel(true);
	}

	public void addResource(Resource resource) {
		synchronized (updateLock) {
			for (ResourceHealthChecker resourceHealthChecker : getHealthCheckerValues()) {
				if (resourceHealthChecker.matchResource(resource)) {
					resourceHealthChecker.addResource(resource);
					// 每个资源只匹配优先级最高的探测规则
					break;
				}
			}
		}
	}

	public void removeResource(Resource resource) {
		synchronized (updateLock) {
			for (ResourceHealthChecker resourceHealthChecker : getHealthCheckerValues()) {
				resourceHealthChecker.removeResource(resource);
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy