[spring-projects/spring-boot]更新 Maven 插件的文档以注意使用相同 JMX 端口配置启动和停止目标的重要性

2024-04-12 270 views
1

这是关于 [spring-boot-maven-plugin]

你好 spring-boot-maven-plugin 团队,

我来这里是为了报告似乎存在的问题。目前使用的是最新的2.3.1spring-boot-maven-插件插件,当我在具有配置文件的项目上运行 mvn clean install -Pintegration 时,maven 作业成功运行,但进程挂起。

我看到 Maven 的成功,并且第一次运行总是成功的。但是,在接下来的运行中,它失败了,因为之前的 Maven 运行正在阻塞/挂起/保持。在我运行 maven 命令很久之后,如果我 lsof -i tcp: 7654,我仍然可以看到那里的进程,以及 ps -ef | grep 显示 /Library/Java/.../.../Contents/Home/bin/java -Dspring.application.admin.enabled=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port =7654 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 -cp /Users/...

我是否使用该端口手动终止进程,这会被解锁,我可以再运行一次,直到它再次被阻止。我尝试在一个非常小的样本上进行复制以进行共享,但是,简单的项目似乎不受影响。我当前的一个是maven多模式,其中结构是带有一些常见的非springboot模块的父级,以及其他springboot微服务。我只想在其中之一上运行(集成前测试)和(集成后测试)。但所提到的问题是100%可重现的。

似乎存在 spring-boot-maven-plugin:2.3.1.RELEASE:stop (post-integration-test) 无法杀死进程的问题。

一体化 org.springframework.boot spring-boot-maven-插件 1000 180 -Dspring.application.admin.enabled=true 预集成测试 开始 7654 集成后测试 停止

回答

2

感谢您的报告。问题出在您的自定义配置上。您已将start目标配置为使用端口 7654 连接到应用程序,但保留stop使用默认端口的目标。因此,stop目标认为应用程序已因无法连接而停止。

如果您想使用自定义的启动和停止,您可能需要考虑在插件的配置中配置一次,而不是在每次执行的配置中配置:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <jmxPort>7654</jmxPort>
    </configuration>
    <executions>
        <execution>
            <id>pre-integration-test</id>
            <goals>
                <goal>start</goal>
            </goals>
        </execution>
        <execution>
            <id>post-integration-test</id>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

我将继续解决这个问题,因为我认为我们可以改进文档以注意到使用相同的开始和停止目标的重要性jmxPort。我们也许还可以在 Maven 运行时做一些事情来检测错误配置。

7

你好安迪,

非常感谢您的详细回答。我跟着你的脚步,有点坏消息,它仍然挂着。 (我不是在挑战,只是讲述一个事实。再次感谢您对此进行调查)

所以,我将属性“向上”移动:

  <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <wait>1000</wait>
                            <maxAttempts>180</maxAttempts>
                            <jmxPort>7654</jmxPort>
                            <environmentVariables>
                                ...
                            </environmentVariables>
                            <jvmArguments>
                                -Dspring.application.admin.enabled=true
                            </jvmArguments>
                        </configuration>
                        <executions>
                            <execution>
                                <id>pre-integration-test</id>
                                <goals>
                                    <goal>start</goal>
                                </goals>
                            </execution>
                            <execution>
                                <id>post-integration-test</id>
                                <goals>
                                    <goal>stop</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>

并且执行后,进程仍然处于hang状态。我仍然可以看到该进程挂在端口 7654 上,以及 ps -ef | 之后存在的进程。 grep 也许我做错了什么?再次感谢你@wilkinsona

2

不幸的是,仅凭 XML 片段很难判断您是否做错了什么。您可以运行 Maven-X并检查输出,看看是否可以发现问题。或者,如果您希望我们花更多时间进行调查,请花一些时间提供重现问题的完整但最小的示例。您可以通过将其推送到 GitHub 上的单独存储库或将其压缩并附加到此问题来与我们共享。

9

我明白了,有道理。

首先是调试日志。正如您可以想象的那样,调试日志非常重要。我粘贴了我认为可以提供帮助的内容,但如果您正在寻找任何特别的内容,请随时告诉我。

[INFO] --- spring-boot-maven-plugin:2.3.1.RELEASE:start (pre-integration-test) @  ---
[DEBUG] Configuring mojo org.springframework.boot:spring-boot-maven-plugin:2.3.1.RELEASE:start from plugin realm ClassRealm[plugin>org.springframework.boot:spring-boot-maven-plugin:2.3.1.RELEASE, parent: jdk.internal.loader.ClassLoaders$AppClassLoader@2c13da15]
[DEBUG] Configuring mojo 'org.springframework.boot:spring-boot-maven-plugin:2.3.1.RELEASE:start' with basic configurator -->
[DEBUG]   (f) addResources = false
[DEBUG]   (f) agents = []
[DEBUG]   (f) classesDirectory = …/target/classes
[DEBUG]   (f) directories = []
[DEBUG]   (f) environmentVariables = { … }
[DEBUG]   (f) excludes = []
[DEBUG]   (f) folders = []
[DEBUG]   (f) fork = true
[DEBUG]   (f) includes = []
[DEBUG]   (f) jmxPort = 7654
[DEBUG]   (f) jvmArguments = -Dspring.application.admin.enabled=true
[DEBUG]   (f) maxAttempts = 180
[DEBUG]   (f) profiles = []
[DEBUG]   (f) project = MavenProject: … @ …/pom.xml
[DEBUG]   (f) session = org.apache.maven.execution.MavenSession@183ade54
[DEBUG]   (f) skip = false
[DEBUG]   (f) useTestClasspath = false
[DEBUG]   (f) wait = 1000
[DEBUG] -- end configuration --
[INFO] Attaching agents: []
[DEBUG] JVM argument(s): -Dspring.application.admin.enabled=true -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=7654 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1
[DEBUG] Classpath for forked process: [If I use ps -ef | grep, this is exactly what I see here when the process hang]
[DEBUG] Application argument(s): --spring.application.admin.enabled=true --spring.application.admin.jmx-name=org.springframework.boot:type=Admin,name=SpringApplication
[DEBUG] Environment variable(s): …
[DEBUG] Connecting to local MBeanServer at port 7654
[DEBUG] Waiting for spring application to start...
[DEBUG] MBean server at port 7654 is not up yet...
[DEBUG] Spring application is not ready yet, waiting 1000ms (attempt 1)
[DEBUG] Connected to local MBeanServer at port 7654
[DEBUG] Waiting for spring application to start...
[DEBUG] Spring application is not ready yet, waiting 1000ms (attempt 1)

此时我的启动应用程序启动。启动没有问题,并且故障保护功能正在发挥作用

[INFO] --- spring-boot-maven-plugin:2.3.1.RELEASE:stop (post-integration-test) @ … ---
[DEBUG] Configuring mojo org.springframework.boot:spring-boot-maven-plugin:2.3.1.RELEASE:stop from plugin realm ClassRealm[plugin>org.springframework.boot:spring-boot-maven-plugin:2.3.1.RELEASE, parent: jdk.internal.loader.ClassLoaders$AppClassLoader@2c13da15]
[DEBUG] Configuring mojo 'org.springframework.boot:spring-boot-maven-plugin:2.3.1.RELEASE:stop' with basic configurator -->
[DEBUG]   (f) jmxPort = 7654
[DEBUG]   (f) project = MavenProject: … @ …/pom.xml
[DEBUG]   (f) skip = false
[DEBUG] -- end configuration --
[INFO] Stopping application...
07-20 19:54:32  INFO - [-127.0.0.1] gistrar$SpringApplicationAdmin : [, ] Application shutdown requested.
07-20 19:54:32  INFO - [-127.0.0.1] .s.s.c.ThreadPoolTaskScheduler : [, ] Shutting down ExecutorService
[INFO] 
[INFO] --- maven-failsafe-plugin:3.0.0-M5:verify (default) @ … ---

这有帮助吗?

顺便问一下,是否可以在 stop 中设置调试日志来表示与 [DEBUG] Connected to local MBeanServer at port 7654 相反的情况?

就像是

[DEBUG] Disconnected from local MBeanServer at port 7654 successfully.

或者

[DEBUG] Failed to disconnect from local MBeanServer at port 7654.

感谢您的帮助。

3

调试输出旨在帮助您诊断问题。正如我上面所说,如果您希望我们花更多时间进行调查,请花一些时间提供一个完整但最小的样本来重现该问题。我从调试输出中可以看到您的应用程序已停止。如果 JVM 尚未退出,则必须有一个或多个非守护线程仍在运行并保持 JVM 处于活动状态。这表明您的应用程序或其配置存在问题,因为它正在启动一个在应用程序上下文关闭时未清理的线程。重现问题的样本将使我们能够确定原因。

2

正如 #19048 中所发现的,我认为我们应该利用这个问题来强化默认端口可能已被占用的事实。这种情况在 Windows 上似乎更常见。

2

我遇到了这个问题,我使用旧版本的插件(2.1.6.RELEASE)修复了它。幸运的是,它适用于最新的 Spring Boot 版本(2.7.0)

1

@italktothewind 感谢您尝试提供帮助,但这样的混合版本不受支持,并且可能会导致意外问题。

8

我在最近开始开发的一个应用程序上遇到了这个问题,并且我已经设法在示例应用程序上重现它,但仍然不清楚为什么会发生这种情况,可能是由于我对 jvm 中线程的理解有限。为了重现,您需要定义一个不同的 TaskScheduler。所以我们有一个像这样的bean:

  @Bean
  public TaskScheduler taskScheduler() {
        return new ConcurrentTaskScheduler();
    }

您需要一个与此类似的计划任务:

    @Scheduled(fixedRate = 1800000)
    public void runScheduledTask() {
        System.out.println("Running scheduledTask");
    }

然后插件看起来像这样。请注意,如果我们使用 fork=false 运行它,一切都会完美运行,但在特殊情况下这不是一个选项:

<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <version>2.7.1</version>
  <configuration>
      <jvmArguments>
          -Dspring.application.admin.enabled=true
      </jvmArguments>
  </configuration>
  <executions>
      <execution>
          <id>pre-integration-test</id>
          <goals>
              <goal>start</goal>
            </goals>
        </execution>
        <execution>
            <id>post-integration-test</id>
            <goals>
              <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

然后我们只要运行mvn verify,端口 9001 上的进程就永远不会终止。有关我创建的存储库的完整工作示例,请参阅:https://github.com/PatrikKoskenniemi/SampleSchedulingProblem

我们可以删除 ConcurrentTaskScheduler bean 并使其工作,但感觉我在这里遗漏了一些东西,也许其他人知道为什么会发生这种情况?

1

@PatrikKoskenniemi 我不明白你的评论和这个问题之间的联系。此问题已关闭,请创建一个单独的问题。我最好的猜测是调度程序阻止应用程序关闭。我不知道我们是否有办法强制它退出,但值得研究。

8

@snicoll从上面我可以看到,它从未得到解决并且实际上关闭,因为它不能以简单的方式重现。因此,我的评论和问题之间的联系是,我提供了解决问题所需的示例应用程序。在我看来,重新打开这个问题是有意义的,但如果你愿意这样的话,我显然可以打开一个新问题?两者都适合我。

7

@PatrikKoskenniemi 我不会那样阅读问题历史记录。记者为启动和停止目标配置了不同的端口,并改进了文档以警告用户此问题。 “悬挂”是唯一与您的示例项目模糊匹配的东西。无论您的问题是否相似,我们都无法重新打开 2 年前发布的文档问题。