[spring-projects/spring-boot]使用 Jetty 时,JVM 直到 Jetty 的线程空闲超时时间过去后才会退出

2024-06-26 911 views
8

不确定这是 Spring Boot 的问题还是 Vaadin 的问题,但从 Spring Boot 2.4.5 升级到 2.4.6 会导致我们的集成测试失败(https://github.com/vaadin/spring/issues/810),因为 RMI 端口(9001)即使在spring-boot:stop执行后仍在使用中。

服务器进程似乎仍在运行:

61070 s018  S      0:13.03 /Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home/jre/bin/java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9001 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 -cp lots-of-classes-here com.vaadin.flow.spring.scan.test.TestServletInitializer --spring.application.admin.enabled=true --spring.application.admin.jmx-name=org.springframework.boot:type=Admin,name=SpringApplication

等待一段时间后它才会消失。

我无法立即从 Java 堆栈跟踪或其他任何因素看出服务器保持运行的原因。

它似乎可以通过我们的任何测试模块重现,只需要

     <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <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 install

有任何想法吗?

回答

2

Spring Boot 2.5.0 也出现了同样的情况

0

@Artur- 我一时想不起来是什么原因导致的。您能否提供一个小型示例应用程序,让我们运行它来重现这个问题?

8

如果您希望我们查看此问题,请提供所需信息。如果未在接下来的 7 天内提供信息,此问题将被关闭。

9

由于缺少所需反馈而关闭。如果您希望我们查看此问题,请提供所需信息,我们将重新打开此问题。

4

@Artur- 您能否分享我们请求的示例应用程序,以便我们有望取得进展? 可能有某种原因阻止服务器停止,我真的不知道可能是什么原因,尤其是在维护版本中。

4

我在 spring boot 之间进行了 git bisect v2.4.5v2.4.6结果

b6e860b2d431b104f47b20feae4c49c3446c3cb6 is the first bad commit
commit b6e860b2d431b104f47b20feae4c49c3446c3cb6
Author: Andy Wilkinson <wilkinsona@vmware.com>
Date:   Wed May 19 19:02:24 2021 +0100

    Prevent Jetty from delaying shutdown beyond grace period

    Fixes gh-22689

我还尝试过签出v2.4.7、恢复b6e860b2d431b104f47b20feae4c49c3446c3cb6,这使我们的测试通过

6

这很奇怪。减少超时应该会导致 Jetty 更积极地关闭,而不是更不积极地关闭。不幸的是,我认为在 Boot 本身中恢复 b6e860b2 不是一个好选择。用户可以自己配置超时,因此更改默认值只会掩盖问题而不是解决问题,让任何自己调整超时的人都无法发现问题。

我真的很想了解为什么 Jetty 没有按预期关闭。为此,我认为我们确实需要一些可以遵循的步骤来重现问题。@Artur- 设置运行 Vaadin 构建的相关部分(我认为这就是 https://github.com/vaadin/spring/issues/810 中的各种命令正在执行的操作mvn以重现问题有多困难?

9

我使用 Java 8 进行了如下测试:

git clone git@github.com:vaadin/spring.git
cd spring
# edit pom.xml to change Spring Boot version to 2.4.6
mvn install -DskipTests 

它需要一段时间并在其中一个测试模块中失败,例如:

[INFO] --- spring-boot-maven-plugin:2.4.6:start (pre-integration-test) @ test-ts-services ---
[INFO] Attaching agents: []
Error: Exception thrown by the agent : java.rmi.server.ExportException: Port already in use: 9001; nested exception is: 
    java.net.BindException: Address already in use (Bind failed)
sun.management.AgentConfigurationError: java.rmi.server.ExportException: Port already in use: 9001; nested exception is: 
    java.net.BindException: Address already in use (Bind failed)
    at sun.management.jmxremote.ConnectorBootstrap.startRemoteConnectorServer(ConnectorBootstrap.java:480)
    at sun.management.Agent.startAgent(Agent.java:262)
    at sun.management.Agent.startAgent(Agent.java:452)
Caused by: java.rmi.server.ExportException: Port already in use: 9001; nested exception is: 
    java.net.BindException: Address already in use (Bind failed)
    at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:346)
    at sun.rmi.transport.tcp.TCPTransport.exportObject(TCPTransport.java:254)
    at sun.rmi.transport.tcp.TCPEndpoint.exportObject(TCPEndpoint.java:412)
    at sun.rmi.transport.LiveRef.exportObject(LiveRef.java:147)
    at sun.rmi.server.UnicastServerRef.exportObject(UnicastServerRef.java:237)
    at sun.rmi.registry.RegistryImpl.setup(RegistryImpl.java:213)
    at sun.rmi.registry.RegistryImpl.<init>(RegistryImpl.java:173)
    at sun.management.jmxremote.SingleEntryRegistry.<init>(SingleEntryRegistry.java:49)
    at sun.management.jmxremote.ConnectorBootstrap.exportMBeanServer(ConnectorBootstrap.java:816)
    at sun.management.jmxremote.ConnectorBootstrap.startRemoteConnectorServer(ConnectorBootstrap.java:468)
    ... 2 more
Caused by: java.net.BindException: Address already in use (Bind failed)
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)
    at java.net.ServerSocket.bind(ServerSocket.java:390)
    at java.net.ServerSocket.<init>(ServerSocket.java:252)
    at java.net.ServerSocket.<init>(ServerSocket.java:143)
    at sun.rmi.transport.proxy.RMIDirectSocketFactory.createServerSocket(RMIDirectSocketFactory.java:45)
    at sun.rmi.transport.proxy.RMIMasterSocketFactory.createServerSocket(RMIMasterSocketFactory.java:345)
    at sun.rmi.transport.tcp.TCPEndpoint.newServerSocket(TCPEndpoint.java:670)
    at sun.rmi.transport.tcp.TCPTransport.listen(TCPTransport.java:335)
    ... 11 more
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for vaadin-spring-parent 18.0-SNAPSHOT:
[INFO] 
[INFO] vaadin-spring-parent ............................... SUCCESS [  0.281 s]
[INFO] vaadin-spring ...................................... SUCCESS [  5.697 s]
[INFO] Vaadin Spring tests ................................ SUCCESS [  0.353 s]
[INFO] Flow Spring Common UI components ................... SUCCESS [  1.418 s]
[INFO] Vaadin Spring Boot integration tests ............... SUCCESS [ 30.510 s]
[INFO] Vaadin Spring Boot integration tests with custom packages to scan SUCCESS [ 28.188 s]
[INFO] Vaadin Spring Boot deployable integration tests .... SUCCESS [ 48.002 s]
[INFO] Vaadin Spring Boot integration tests when deployed using a context path SUCCESS [ 37.195 s]
[INFO] Integration tests for V15+ endpoints ............... FAILURE [01:00 min]
[INFO] Integration tests for V15+ endpoints (custom Connect client) SKIPPED
[INFO] Integration tests for a Spring MVC project without using endpoints SKIPPED
[INFO] Integration tests for Vaadin Spring Security and Flow SKIPPED
[INFO] Integration tests for Vaadin Spring Security and Flow With Context Path SKIPPED
[INFO] Integration tests for Vaadin Spring Security and Fusion SKIPPED
[INFO] Integration tests for Vaadin Spring Security and Fusion With Context Path SKIPPED
[INFO] Keep this module as the last one in the list ....... SKIPPED
3

谢谢,@Artur-。

原因似乎是 Jetty 中的一个错误QueuedThreadPool。如果停止超时为零,它会让线程继续运行。它们最终会在 60 秒后退出,这是默认的空闲超时。如果停止超时仅为 1ms,JVM 几乎会立即退出。我打开了https://github.com/eclipse/jetty.project/issues/6400

让我们看看 Jetty 团队怎么说。如果我误解了QueuedThreadPool应该如何表现,或者修复无法及时用于下一个 Spring Boot 版本,我们可以将 Boot 中的默认停止超时从 0ms 更改为 1ms。与此同时,可以使用定制器 bean 来增加超时来解决该问题:

@Bean
JettyServerCustomizer stopTimeoutCustomizer() {
    return (server) -> server.setStopTimeout(1);
}
2

我已将其分配给 2.4.8,以便我们不会忘记在下一个版本之前对其进行处理。

2

我们将在适当的时候升级到 Jetty 9.4.43,它将修复此QueuedThreadPool问题。它似乎无法及时发布,以赶上明天的 Boot 版本,但是,与其在一个版本中更改超时时间,然后在下一个版本中将其改回,我们建议受此问题影响的任何人都暂时配置上述解决方法。

9

Jetty 9.4.43 现已发布