You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SpringBoot关闭时暂停应用,让Prometheus采集最后15秒指标?

问题描述

我们的SpringBoot应用使用Micrometer生成指标,Prometheus每15秒采集一次。当应用关闭(如Pod重启)时,可能会丢失最后15秒的指标数据。除推送指标、持久化指标等方案外,我想尝试在关闭时暂停应用:停止运行业务代码(避免计数器继续增长),同时保持/actuator/prometheus端点可用,等待Prometheus完成最后一次采集。

我曾尝试在@PreDestroy中使用Thread.sleep(),也试过设置标记,但无论用哪种钩子,操作都为时已晚——/actuator/prometheus已经关闭。请问如何实现这种暂停逻辑?是否有触发足够早的钩子能确保Actuator端点仍正常工作?

解决方案

1. 用SmartLifecycle控制关闭顺序

SmartLifecycle能自定义Bean的启动/关闭优先级,你可以让业务组件先停止,Actuator相关组件最后关闭,确保Prometheus端点在业务暂停后仍能访问。

实现示例:

首先定义一个业务生命周期管理器,控制业务代码的执行开关,并设置较高的关闭优先级:

@Component
public class BusinessLifecycleManager implements SmartLifecycle {
    private volatile boolean running = false;
    public volatile boolean allowBusinessProcessing = true;

    @Override
    public void start() {
        running = true;
        allowBusinessProcessing = true;
    }

    @Override
    public void stop() {
        // 先禁止业务代码执行
        allowBusinessProcessing = false;
        // 等待15秒,给Prometheus留足采集时间
        try {
            Thread.sleep(15000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        running = false;
    }

    @Override
    public boolean isRunning() {
        return running;
    }

    // 数值越小,关闭优先级越高(先执行)
    @Override
    public int getPhase() {
        return 0; // Actuator默认优先级为2147483647,会在之后关闭
    }
}

然后在业务代码中注入这个管理器,判断是否允许执行:

@Service
public class BusinessService {
    @Autowired
    private BusinessLifecycleManager lifecycleManager;

    public void processBusinessTask() {
        if (!lifecycleManager.allowBusinessProcessing) {
            return; // 停止业务逻辑
        }
        // 原有业务代码
        // ...
    }
}

2. 监听ContextClosedEvent并延迟上下文关闭

通过监听Spring的ContextClosedEvent,在上下文开始关闭时立即暂停业务,然后延迟一段时间再让关闭流程继续,这段时间内Actuator端点依然可用。

实现示例:

@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class ShutdownDelayListener implements ApplicationListener<ContextClosedEvent> {
    @Autowired
    private BusinessLifecycleManager lifecycleManager;

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        // 立即暂停业务
        lifecycleManager.allowBusinessProcessing = false;
        // 延迟15秒,等待Prometheus完成最后一次采集
        try {
            Thread.sleep(15000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        // 延迟结束后,上下文会继续执行关闭流程
    }
}

@Order(Ordered.HIGHEST_PRECEDENCE)确保这个监听器最先触发,早于Actuator的关闭逻辑。

3. 自定义Prometheus端点的关闭时机

通过自定义EndpointShutdownHandler,单独控制Prometheus端点的关闭时间,让它在最后才关闭:

@Configuration
public class ActuatorShutdownConfig {
    @Bean
    public EndpointShutdownHandler prometheusEndpointShutdownHandler() {
        return (context, endpointId) -> {
            if ("prometheus".equals(endpointId)) {
                // 延迟15秒再关闭Prometheus端点
                try {
                    Thread.sleep(15000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        };
    }
}

配合业务逻辑的暂停机制,就能实现业务停止后,Prometheus端点仍能提供指标的效果。

内容的提问来源于stack exchange,提问作者R2C2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 19:22:39