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

com.alipay.sofa.koupleless.arklet.springboot.starter.health.BaseProbeAvailabilityStateHandler Maven / Gradle / Ivy

/*
 * 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 com.alipay.sofa.koupleless.arklet.springboot.starter.health;

import com.alipay.sofa.ark.api.ArkClient;
import com.alipay.sofa.ark.spi.event.AbstractArkEvent;
import com.alipay.sofa.ark.spi.event.biz.AfterBizStartupFailedEvent;
import com.alipay.sofa.ark.spi.event.biz.AfterBizStartupEvent;
import com.alipay.sofa.ark.spi.event.biz.AfterBizStopEvent;
import com.alipay.sofa.ark.spi.event.biz.BeforeBizStartupEvent;
import com.alipay.sofa.ark.spi.event.biz.BeforeBizStopEvent;
import com.alipay.sofa.ark.spi.model.Biz;
import com.alipay.sofa.ark.spi.service.event.EventHandler;
import org.springframework.boot.availability.ApplicationAvailability;
import org.springframework.boot.availability.ApplicationAvailabilityBean;
import org.springframework.boot.availability.AvailabilityChangeEvent;
import org.springframework.boot.availability.LivenessState;
import org.springframework.boot.availability.ReadinessState;
import org.springframework.context.ApplicationContext;

import java.util.concurrent.CopyOnWriteArraySet;

import static com.alipay.sofa.koupleless.common.util.SpringUtils.getBean;

/**
 * @author [email protected]
 * @version $Id: BaseProbeAvailibity.java, v 0.1 2024年07月04日 12:56 立蓬 Exp $
 */
public class BaseProbeAvailabilityStateHandler implements EventHandler {

    private final CopyOnWriteArraySet startingBizSet = new CopyOnWriteArraySet<>();

    private boolean                        associateWithAllBizReadiness;

    private int                            silenceSecondsBeforeUninstall;

    private ApplicationContext             baseContext;
    private final ApplicationAvailability  applicationAvailability;

    public BaseProbeAvailabilityStateHandler(ApplicationContext applicationContext,
                                             boolean withAllBizReadiness,
                                             int silenceSecondsBeforeUninstall) {
        baseContext = applicationContext;
        associateWithAllBizReadiness = withAllBizReadiness;
        applicationAvailability = (ApplicationAvailability) baseContext
            .getBean("applicationAvailability");
        this.silenceSecondsBeforeUninstall = silenceSecondsBeforeUninstall;
    }

    @Override
    public int getPriority() {
        return LOWEST_PRECEDENCE;
    }

    @Override
    public void handleEvent(AbstractArkEvent event) {
        Object obj = event.getSource();
        if (obj instanceof Biz) {
            Biz biz = (Biz) obj;
            handleBizEvent(event, biz);
        }
    }

    private void handleBizEvent(AbstractArkEvent event, Biz biz) {
        if (biz == ArkClient.getMasterBiz()) {
            return;
        }

        if (!associateWithAllBizReadiness) {
            return;
        }

        // 模块启动前,关闭流量,添加该模块
        if (event instanceof BeforeBizStartupEvent) {
            AvailabilityChangeEvent.publish(baseContext, ReadinessState.REFUSING_TRAFFIC);
            startingBizSet.add(biz);
            return;
        }

        // 模块启动失败,保持流量关闭
        if (event instanceof AfterBizStartupFailedEvent) {
            AvailabilityChangeEvent.publish(baseContext, ReadinessState.REFUSING_TRAFFIC);
            return;
        }

        // 模块启动后,如果基座本身 ready 且所有正在启动的模块都 ready,那么开启流量
        if (event instanceof AfterBizStartupEvent) {
            if (applicationAvailability.getLivenessState() == LivenessState.CORRECT
                && getCompositeStartingBizReadiness() == ReadinessState.ACCEPTING_TRAFFIC) {
                AvailabilityChangeEvent.publish(baseContext, ReadinessState.ACCEPTING_TRAFFIC);
            }
            return;
        }

        // 模块卸载前:关闭流量
        if (event instanceof BeforeBizStopEvent) {
            AvailabilityChangeEvent.publish(baseContext, ReadinessState.REFUSING_TRAFFIC);
            silenceBeforeUninstall(silenceSecondsBeforeUninstall);
            return;
        }

        // 模块卸载后,移除该模块
        if (event instanceof AfterBizStopEvent) {
            startingBizSet.remove(biz);
        }
    }

    private void silenceBeforeUninstall(int seconds) {
        if (seconds > 0) {
            try {
                Thread.sleep(seconds * 1000L);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }

    }

    private ReadinessState getCompositeStartingBizReadiness() {
        if (startingBizSet.stream()
            .allMatch(biz -> getReadinessState(biz) == ReadinessState.ACCEPTING_TRAFFIC)) {
            return ReadinessState.ACCEPTING_TRAFFIC;
        }
        return ReadinessState.REFUSING_TRAFFIC;
    }

    private ReadinessState getReadinessState(Biz biz) {
        try {
            ApplicationAvailabilityBean applicationAvailability = (ApplicationAvailabilityBean) getBean(
                biz, "applicationAvailability");
            return applicationAvailability.getReadinessState();
        } catch (Exception e) {
            return ReadinessState.REFUSING_TRAFFIC;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy