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

cn.hippo4j.springboot.starter.remote.AbstractHealthCheck Maven / Gradle / Ivy

There is a newer version: 1.5.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 cn.hippo4j.springboot.starter.remote;

import cn.hippo4j.springboot.starter.event.ApplicationCompleteEvent;
import cn.hippo4j.springboot.starter.core.ShutdownExecuteException;
import cn.hippo4j.core.executor.support.ThreadFactoryBuilder;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationListener;

import java.util.Objects;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import static cn.hippo4j.common.constant.Constants.HEALTH_CHECK_INTERVAL;

/**
 * Abstract health check.
 *
 * @author chen.ma
 * @date 2021/12/8 20:19
 */
@Slf4j
public abstract class AbstractHealthCheck implements ServerHealthCheck, InitializingBean, ApplicationListener {

    /**
     * Health status
     */
    private volatile boolean healthStatus = true;

    /**
     * Client shutdown hook
     */
    private volatile boolean clientShutdownHook = false;

    /**
     * Spring context init complete. TODO: Why this
     */
    private boolean contextInitComplete = false;

    /**
     * Health main lock
     */
    private final ReentrantLock healthMainLock = new ReentrantLock();

    /**
     * Health condition
     */
    private final Condition healthCondition = healthMainLock.newCondition();

    /**
     * Health check executor
     */
    private final ScheduledThreadPoolExecutor healthCheckExecutor = new ScheduledThreadPoolExecutor(
            new Integer(1),
            ThreadFactoryBuilder.builder().daemon(true).prefix("client.scheduled.health.check").build());

    /**
     * Send health check.
     *
     * @return
     */
    protected abstract boolean sendHealthCheck();

    /**
     * Health check.
     */
    public void healthCheck() {
        boolean healthCheckStatus = sendHealthCheck();
        if (healthCheckStatus) {
            if (Objects.equals(healthStatus, false)) {
                healthStatus = true;
                log.info("The client reconnects to the server successfully.");
                signalAllBizThread();
            }
        } else {
            healthStatus = false;
        }
    }

    @Override
    @SneakyThrows
    public boolean isHealthStatus() {
        while (contextInitComplete
                && !healthStatus && !clientShutdownHook) {
            healthMainLock.lock();
            try {
                healthCondition.await();
            } finally {
                healthMainLock.unlock();
            }
        }
        if (!healthStatus) {
            throw new ShutdownExecuteException();
        }
        return healthStatus;
    }

    @Override
    public void setHealthStatus(boolean healthStatus) {
        healthMainLock.lock();
        try {
            this.healthStatus = healthStatus;
            log.warn("The server health status setting is unavailable.");
        } finally {
            healthMainLock.unlock();
        }
    }

    /**
     * Signal all biz thread.
     */
    private void signalAllBizThread() {
        healthMainLock.lock();
        try {
            healthCondition.signalAll();
        } finally {
            healthMainLock.unlock();
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        /**
         * Add a hook function, when the client stops, if the server is in an unhealthy state,
         * the client destroy function will suspend operation
         */
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            clientShutdownHook = true;
            signalAllBizThread();
        }));
        healthCheckExecutor.scheduleWithFixedDelay(() -> healthCheck(), 0, HEALTH_CHECK_INTERVAL, TimeUnit.SECONDS);
    }

    @Override
    public void onApplicationEvent(ApplicationCompleteEvent event) {
        contextInitComplete = true;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy