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

Spring Boot 2.7优雅关闭时SSE连接未终止,如何通过钩子处理?

Spring Boot 2.7优雅关闭时主动终止SSE连接的解决方案

你遇到的问题是因为SSE长连接属于活跃请求,Tomcat在优雅关闭时会等待这类连接自行结束,但SSE通常是永久连接,最终触发超时并终止优雅关闭流程。@PreDestroy无法解决该问题,因为它的执行时机在上下文销毁阶段,此时优雅关闭的等待阶段已经结束。

以下是可行的解决方法:

方法一:监听ContextClosedEvent主动关闭所有SSE连接

Spring的ContextClosedEvent会在优雅关闭流程启动时触发(早于Bean销毁阶段),我们可以利用这个事件主动终止所有活跃的SSE连接:

  1. 创建SSE连接管理器:维护所有活跃的SseEmitter实例,同时自动清理失效连接
@Component
public class SseConnectionManager {
    private final List<SseEmitter> activeEmitters = new CopyOnWriteArrayList<>();

    public void addEmitter(SseEmitter emitter) {
        activeEmitters.add(emitter);
        // 注册回调,自动移除已完成/超时的连接
        emitter.onCompletion(() -> activeEmitters.remove(emitter));
        emitter.onTimeout(() -> activeEmitters.remove(emitter));
    }

    public void closeAllEmitters() {
        activeEmitters.forEach(emitter -> {
            try {
                // 主动标记连接完成,客户端会收到结束信号
                emitter.complete();
            } catch (Exception ignore) {
                // 忽略关闭时的异常,比如连接已被客户端断开
            }
        });
        activeEmitters.clear();
    }
}
  1. 注册上下文关闭事件监听器:在关闭开始时调用管理器的关闭方法
@Component
public class SseShutdownListener implements ApplicationListener<ContextClosedEvent> {
    private final SseConnectionManager connectionManager;

    public SseShutdownListener(SseConnectionManager connectionManager) {
        this.connectionManager = connectionManager;
    }

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        // 优雅关闭启动时,立即关闭所有SSE长连接
        connectionManager.closeAllEmitters();
    }
}
  1. 在SSE接口中使用管理器:创建SseEmitter时加入管理器
@RestController
@RequestMapping("/sse")
public class SseController {
    private final SseConnectionManager connectionManager;

    public SseController(SseConnectionManager connectionManager) {
        this.connectionManager = connectionManager;
    }

    @GetMapping("/stream")
    public SseEmitter stream() {
        SseEmitter emitter = new SseEmitter();
        connectionManager.addEmitter(emitter);
        // 这里添加你的SSE消息发送逻辑,省略
        return emitter;
    }
}

配置完成后,触发优雅关闭时ContextClosedEvent会立即触发,管理器主动关闭所有SSE连接,Tomcat检测不到活跃请求后会直接完成优雅关闭,不会等待超时。

方法二:缩短Tomcat优雅关闭超时时间(可选)

如果仅需缩短等待时长而非主动关闭连接,可以在application.properties中配置:

server.tomcat.graceful-shutdown-timeout=5s

但这种方法只是减少等待时长,不如主动关闭彻底,因为SSE连接不会自行终止,仍会等到超时才结束。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 11:55:25