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

Spring Boot优雅关闭超时未完成任务时如何实现日志记录回调

Spring Boot 优雅关闭超时自定义日志实现方案

你当前使用的是Spring Boot官方提供的标准优雅关闭配置:

server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=1m

要实现等待超时仍有未完成任务时打印自定义日志,完全可以做到,不需要改动原有优雅关闭的核心逻辑,下面是两种低侵入的实现方式:

方式一:容器事件监听(推荐,适配所有内嵌服务器)

Spring容器关闭阶段如果等待超时,会直接中断未完成的生命周期回调走强制退出流程,你可以通过两个步骤实现自定义日志打印:

  • 先做一个轻量的运行中任务持有组件,业务代码里处理请求、执行异步任务的时候把任务标识注册进去,任务执行完成就移除标识,不需要侵入核心业务逻辑。
  • 写一个最高优先级的ContextClosedEvent事件监听器,在监听器里判断当前是否还有未完成的任务,如果有就说明触发了关闭超时,直接打印你需要的日志内容。

参考代码:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE) // 最高优先级,保证日志逻辑在容器销毁前执行
public class ShutdownTimeoutLogListener implements ApplicationListener<ContextClosedEvent> {
    private static final Logger log = LoggerFactory.getLogger(ShutdownTimeoutLogListener.class);

    @Autowired
    private RunningTaskRepository runningTaskRepository; // 自定义的运行中任务存储组件

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        Set<String> unFinishedTasks = runningTaskRepository.getAllRunningTaskIds();
        if (!unFinishedTasks.isEmpty()) {
            log.warn("优雅关闭等待1分钟超时,当前仍存在{}个未完成任务,任务标识:{}",
                    unFinishedTasks.size(), unFinishedTasks);
        }
    }
}

方式二:自定义内嵌Web服务器的优雅关闭逻辑

如果你只关心Web请求层面的未完成任务,不需要统计自定义异步任务,可以直接扩展对应内嵌服务器的优雅关闭逻辑,在超时分支里加日志,以默认的Tomcat为例:

@Component
public class TomcatGracefulShutdownConfig implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    private static final Logger log = LoggerFactory.getLogger(TomcatGracefulShutdownConfig.class);
    @Value("${spring.lifecycle.timeout-per-shutdown-phase:1m}")
    private Duration shutdownTimeout;

    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        factory.addConnectorCustomizers(connector -> {
            ProtocolHandler protocolHandler = connector.getProtocolHandler();
            if (protocolHandler instanceof AbstractProtocol) {
                AbstractProtocol<?> protocol = (AbstractProtocol<?>) protocolHandler;
                factory.setGracefulShutdown(() -> {
                    long startTimestamp = System.currentTimeMillis();
                    // 循环等待活跃请求处理完成
                    while (System.currentTimeMillis() - startTimestamp < shutdownTimeout.toMillis()) {
                        if (protocol.getActiveCount() == 0) {
                            return;
                        }
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                    // 执行到此处说明等待超时
                    log.warn("Tomcat优雅关闭超时,仍有{}个活跃请求未处理完成,将强制关闭", protocol.getActiveCount());
                });
            }
        });
    }
}

如果使用Jetty、Undertow作为内嵌服务器,实现逻辑一致,只需要替换对应服务器的API获取活跃请求数即可。

补充说明

如果不需要打印具体的未完成任务明细,只是想感知超时事件,直接把org.springframework.boot.lifecycle包的日志级别调整为warn,就能看到框架原生打印的超时提示日志,不需要额外写代码。
所有自定义的关闭逻辑注意控制执行耗时,不要阻塞容器正常退出流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 20:12:16