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

ECS部署的Spring WebFlux应用@PreDestroy在实例终止时未触发

问题描述

我有一个部署在ECS上的Spring WebFlux应用,期望在实例缩容或终止(部署等场景)时,执行Processor.java中的@PreDestroy方法。本地在IntelliJ中运行应用,停止时@PreDestroy注解方法可正常触发,但部署到ECS后该方法不生效。我了解到通过shell脚本运行应用时,shell会吸收信号不传递给应用,因此在entrypoint.sh中使用了exec命令,但问题仍未解决。

相关代码

Dockerfile

ARG OPENJDK_DIGEST
FROM openjdk:8-jre@${OPENJDK_DIGEST}

LABEL org.opencontainers.image.authors="xxxx.xxx.com"

VOLUME /tmp
ARG JAR_FILE
ARG PROFILE
ADD ${JAR_FILE} app.jar
ENV PROFILE_ENV=${PROFILE}
EXPOSE 8080
COPY entrypoint.sh /
COPY job.sh /
COPY tini-arm64 /
ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

# Execute the Java application
exec java -Dspring.profiles.active=${PROFILE_ENV} \
          -XX:+UseG1GC \
          -Djava.security.egd=file:/dev/./urandom \
          -Dloader.main=com.paytmlabs.adtech.adtechdecisionengine.AdTechDecisionEngineApplication.java \
          -XX:CompressedClassSpaceSize=2g \
          -jar app.jar

Processor.java

@Slf4j
@Component
@DependsOn({"dep1", "dep2", "dep3", "dep4"})
public class AuditSinkEventProcessor extends SinkEventProcessor {

  .
  .
  .

  @PreDestroy
  public void destroy() {
    this.stopSink();
    this.processParquetFiles(true);
  }
}
解决建议
  • 调整ECS任务停止超时时间
    ECS默认停止超时为30秒,若@PreDestroy方法执行耗时超过这个时间,ECS会直接发送SIGKILL强制终止进程,导致清理逻辑无法完成。在任务定义中修改stopTimeout参数,设置为足够覆盖清理逻辑的时长(如60秒)。

  • 启用Tini处理信号传递
    容器中已包含tini-arm64,但未启用。Tini作为PID 1进程能更可靠地转发信号给子进程。修改Dockerfile的ENTRYPOINT:

    ENTRYPOINT ["/tini-arm64", "--", "/entrypoint.sh"]
    
  • 验证信号是否到达Java进程
    在entrypoint.sh开头添加信号捕获日志,确认SIGTERM是否被接收:

    trap 'echo "Received SIGTERM, passing to Java process"' SIGTERM
    

    同时进入容器执行ps aux,确认Java进程是PID 1(exec命令应保证这点,但需验证)。

  • 补充Spring关闭事件监听器
    为确保关闭逻辑被触发,添加ContextClosedEvent监听器作为@PreDestroy的补充:

    @Component
    public class AppShutdownListener implements ApplicationListener<ContextClosedEvent> {
        @Autowired
        private AuditSinkEventProcessor auditProcessor;
    
        @Override
        public void onApplicationEvent(ContextClosedEvent event) {
            log.info("Triggering shutdown cleanup via ContextClosedEvent");
            auditProcessor.destroy();
        }
    }
    
  • 手动测试信号响应
    进入运行中的ECS容器,执行kill -TERM <java-pid>,查看应用日志是否触发destroy()方法。如果本地容器测试正常但ECS上无响应,排查ECS任务的网络或权限配置。

  • 增强日志排查
    在destroy()方法中添加详细日志,比如:

    @PreDestroy
    public void destroy() {
      log.info("Starting pre-destroy cleanup: stopping sink");
      this.stopSink();
      log.info("Processing remaining parquet files");
      this.processParquetFiles(true);
      log.info("Pre-destroy cleanup completed");
    }
    

    通过日志判断方法是否被调用、是否执行完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 01:30:14