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

Aeron代理需SIGKILL才能终止,SpringBoot优雅关闭问题排查

SpringBoot集成Aeron后无法正常终止问题排查

问题描述

基于SpringBoot开发Aeron发布/接收端服务,已通过Runtime.getRuntime().addShutdownHook添加关闭钩子,触发ShutdownSignalBarrier启动优雅关闭流程:

  • onStop()方法等待信号后执行关闭序列
  • close()方法负责释放所有资源避免泄漏

但捕获关闭信号并执行完关闭流程后,应用仍无法正常终止。相关代码如下:

private Aeron aeron;
private AeronArchive aeronArchive;
private Publication publication;
private Subscription subscription;

private AgentRunner sendAgentRunner;
private AgentRunner receiveAgentRunner;

private SimReceiveAgent receiveAgent;
private SimSendAgent sendAgent;


@PostConstruct
public void init() {
    setup();

    receiveAgent = new SimReceiveAgent(subscription, barrier);
    sendAgent = new SimSendAgent(publication, aeron);

    // Construct the subs and pubs Runners
    sendAgentRunner = new AgentRunner(idleStrategySend,
            Throwable::printStackTrace, null, sendAgent);
    receiveAgentRunner = new AgentRunner(idleStrategyReceive,
            Throwable::printStackTrace, null, receiveAgent);

    // Start the subs and pubs
    LOGGER.info("Starting publisher simulator sender thread");
    AgentRunner.startOnThread(sendAgentRunner);

    LOGGER.info("Starting publisher simulator receiver thread");
    AgentRunner.startOnThread(receiveAgentRunner);


    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        LOGGER.info("Shutdown signal received, signaling barrier...");
        barrier.signal();
    }));
}


public void onStop() throws Exception {
    barrier.await();
}


public void close() throws Exception {
    barrier.await();
    LOGGER.info("Attempt to stop application");
    if (timer != null) {
        timer.cancel();
    }

    CloseHelper.quietClose(sendAgentRunner);
    CloseHelper.quietClose(receiveAgentRunner);
    CloseHelper.quietClose(aeron);
    CloseHelper.quietClose(aeronArchive);
}

排查与解决步骤

1. 检查Agent的onClose()实现

AgentRunner.startOnThread()启动的线程会持续运行,直到Agent的onClose()被调用且正确终止核心逻辑。如果你的SimSendAgent和SimReceiveAgent没有实现Agent接口的onClose()方法,或者方法内没有设置终止标记,AgentRunner无法正常停止,线程会一直存活。

确保Agent实现类满足以下要求:

  • 定义线程安全的终止标记(如volatile boolean isRunning)
  • 在onClose()中切换终止标记
  • 核心处理循环中检查标记,一旦为false就退出并返回Agent.AGENT_TERMINATED

示例:

public class SimSendAgent implements Agent {
    private volatile boolean isRunning = true;
    // 其他成员变量...

    @Override
    public void onClose() {
        isRunning = false;
    }

    @Override
    public int doWork() throws Exception {
        if (!isRunning) {
            return Agent.AGENT_TERMINATED; // 通知Runner终止
        }
        // 原有发送逻辑...
        return 0;
    }
}

2. 消除ShutdownHook与Spring生命周期的冲突

SpringBoot的onStop()(若实现SmartLifecycle接口)本身会在应用关闭时被调用,你通过ShutdownHook触发barrier,同时onStop()又等待barrier,可能导致执行顺序混乱或阻塞。

建议调整逻辑:

  • 移除Runtime.getRuntime().addShutdownHook,直接在onStop()中调用close()方法
  • 确保close()内的资源释放顺序正确:先关闭AgentRunner,再关闭Aeron和AeronArchive(当前代码顺序正确,但需确认CloseHelper.quietClose(AgentRunner)能真正终止线程)

3. 标记Agent线程为守护线程

AgentRunner.startOnThread()默认启动非守护线程,这类线程未终止时JVM不会退出。可以手动将线程设置为守护线程:

// 替换原AgentRunner.startOnThread()代码
Thread sendThread = new Thread(sendAgentRunner);
sendThread.setDaemon(true);
sendThread.start();

Thread receiveThread = new Thread(receiveAgentRunner);
receiveThread.setDaemon(true);
receiveThread.start();

4. 替换ShutdownSignalBarrier为可靠实现

若自定义的ShutdownSignalBarrier存在唤醒逻辑缺陷,会导致onStop()或close()一直阻塞。建议用CountDownLatch替代,它的线程安全性和唤醒可靠性更有保障:

// 替换原barrier定义
private final CountDownLatch shutdownLatch = new CountDownLatch(1);

// 触发关闭时调用
shutdownLatch.countDown();

// 等待关闭信号时调用
shutdownLatch.await();

5. 排查未释放的其他资源

除代码中列出的资源,可能还有未关闭的后台线程(如timer关联的线程池、自定义线程等)导致JVM无法退出。可以用以下命令排查存活线程:

jstack <应用进程ID>

定位未终止的线程后,找到对应的资源并添加关闭逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:15:08