iloveeyjafjalla opened a new issue, #11456: URL: https://github.com/apache/rocketmq/issues/11456
### Before Creating the Bug Report - [x] I have searched the [open issues](https://github.com/apache/rocketmq/issues) of this repository and believe that this is not a duplicate. - [x] This is a defect in Apache RocketMQ, not a usage question. - [x] I can reproduce this on the current `develop` branch. ### RocketMQ Version develop @ `57c2dc04f78cc7e73e6b8c9436ee0fff0d0f46c3` (the revision this was verified on) ### Describe the Bug `RemotingProtocolServer` schedules the expired-request cleanup in its constructor: ```java this.timerExecutor = ThreadUtils.newSingleThreadScheduledExecutor( new ThreadFactoryBuilder().setNameFormat("RemotingServerScheduler-%d").build() ); this.timerExecutor.scheduleAtFixedRate(this::cleanExpireRequest, 100, 100, TimeUnit.MILLISECONDS); ``` `ThreadFactoryBuilder` produces **non-daemon** threads, and `shutdown()` stops the eight remoting executors but not this one: ```java this.defaultRemotingServer.shutdown(); this.remotingChannelManager.shutdown(); this.sendMessageExecutor.shutdown(); this.pullMessageExecutor.shutdown(); this.heartbeatExecutor.shutdown(); this.updateOffsetExecutor.shutdown(); this.topicRouteExecutor.shutdown(); this.defaultExecutor.shutdown(); // timerExecutor is never stopped ``` So a proxy whose remoting server has been shut down keeps a live thread running `cleanExpireRequest` every 100 ms against the stopped server, and the non-daemon thread keeps the JVM alive after the Spring context has closed instead of letting the process exit. This is the same shape as #11427: a service created in a constructor is started but not stopped by the owner's shutdown path. ### Steps to Reproduce 1. Start the proxy and stop it again (or close its Spring context in a test). 2. `jstack` shows the `RemotingServerScheduler-1` thread still alive after `RemotingProtocolServer.shutdown()` returned, and the process does not exit on its own. 3. The added test shows the same point without a proxy: with the current code `verify(timerExecutor).shutdown()` fails with `Wanted but not invoked`. ### What Did You Expect to See? `shutdown()` stops the executor it scheduled in the constructor, like the eight remoting executors it already stops, so nothing of the server survives the shutdown. ### What Did You See Instead? The timer thread survives the shutdown, keeps running the 100 ms cleanup task, and keeps the JVM alive. ### Additional Context `#10806` reports a different problem in the same class (the cleanup loop swallows exceptions); this one is about the executor's lifecycle. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
