CloudNetService / CloudNet

A modern application that can dynamically and easily deliver Minecraft oriented software
https://cloudnetservice.eu
Apache License 2.0
372 stars 116 forks source link

Minestom server doesn't shut down correctly #1304

Closed DasBabyPixel closed 4 months ago

DasBabyPixel commented 1 year ago

Stacktrace

No response

Actions to reproduce

Set up a dummy minestom server that starts and stops. The wrapper will not stop because there are some threads that aren't daemons so the wrapper just won't stop even though the application has terminated

        MinecraftServer server = MinecraftServer.init();
        server.start(System.getProperty("service.bind.host"), Integer.getInteger("service.bind.port"));
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        MinecraftServer.stopCleanly();

CloudNet version

[31.08 10:51:24.867] INFO: [31.08 10:51:24.868] INFO: CloudNet Blizzard 4.0.0-RC9 f6ca4c38 [31.08 10:51:24.868] INFO: Discord: https://discord.cloudnetservice.eu/ [31.08 10:51:24.868] INFO: [31.08 10:51:24.869] INFO: ClusterId: deebb2f9--41cd--246e55129822 [31.08 10:51:24.869] INFO: NodeId: Node-1 [31.08 10:51:24.869] INFO: Head-NodeId: Node-1 [31.08 10:51:24.870] INFO: CPU usage: (P/S) .36/.34/100% [31.08 10:51:24.870] INFO: Node services memory allocation (U/R/M): 1536/1536/4096 MB [31.08 10:51:24.871] INFO: Threads: 55 [31.08 10:51:24.871] INFO: Heap usage: 42/256MB [31.08 10:51:24.871] INFO: JVM: Amazon.com Inc. 17 (OpenJDK 64-Bit Server VM 17.0.4.1+9-LTS) [31.08 10:51:24.871] INFO: Update Repo: CloudNetService/launchermeta, Update Branch: beta [31.08 10:51:24.872] INFO:

Other

A potential fix is to make all threads in the wrapper daemon threads. Should be fine because the node shouldn't care if the wrapper just stops responding

Issue uniqueness

Edit: Here is a thread dump of all non-daemon threads

"multithreadEventLoopGroup-1-1" #18 prio=10 os_prio=2 cpu=0.00ms elapsed=89.03s tid=0x000001fe547ef9c0 nid=0x5604 runnable  [0x00000089a82ff000]
   java.lang.Thread.State: RUNNABLE
        at sun.nio.ch.WEPoll.wait(java.base@17.0.4.1/Native Method)
        at sun.nio.ch.WEPollSelectorImpl.doSelect(java.base@17.0.4.1/WEPollSelectorImpl.java:111)
        at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@17.0.4.1/SelectorImpl.java:129)
        - locked <0x00000000e0763928> (a io.netty5.channel.nio.SelectedSelectionKeySet)
        - locked <0x00000000e07638c8> (a sun.nio.ch.WEPollSelectorImpl)
        at sun.nio.ch.SelectorImpl.select(java.base@17.0.4.1/SelectorImpl.java:141)
        at io.netty5.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:62)
        at io.netty5.channel.nio.NioHandler.select(NioHandler.java:578)
        at io.netty5.channel.nio.NioHandler.run(NioHandler.java:361)
        at io.netty5.channel.SingleThreadEventLoop.runIO(SingleThreadEventLoop.java:192)
        at io.netty5.channel.SingleThreadEventLoop.run(SingleThreadEventLoop.java:176)
        at io.netty5.util.concurrent.SingleThreadEventExecutor.lambda$doStartThread$4(SingleThreadEventExecutor.java:774)
        at io.netty5.util.concurrent.SingleThreadEventExecutor$$Lambda$249/0x0000000800d8d248.run(Unknown Source)
        at io.netty5.util.internal.ThreadExecutorMap.lambda$apply$1(ThreadExecutorMap.java:68)
        at io.netty5.util.internal.ThreadExecutorMap$$Lambda$250/0x0000000800d8d468.run(Unknown Source)
        at io.netty5.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(java.base@17.0.4.1/Thread.java:833)

   Locked ownable synchronizers:
        - None

"Packet-Dispatcher-0" #22 prio=5 os_prio=0 cpu=0.00ms elapsed=88.94s tid=0x000001fe54b4a920 nid=0x3ed0 waiting on condition  [0x00000089a87ff000]
   java.lang.Thread.State: WAITING (parking)
        at jdk.internal.misc.Unsafe.park(java.base@17.0.4.1/Native Method)
        - parking to wait for  <0x00000000e07656c0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(java.base@17.0.4.1/LockSupport.java:341)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(java.base@17.0.4.1/AbstractQueuedSynchronizer.java:506)
        at java.util.concurrent.ForkJoinPool.unmanagedBlock(java.base@17.0.4.1/ForkJoinPool.java:3463)
        at java.util.concurrent.ForkJoinPool.managedBlock(java.base@17.0.4.1/ForkJoinPool.java:3434)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@17.0.4.1/AbstractQueuedSynchronizer.java:1623)
        at java.util.concurrent.LinkedBlockingQueue.take(java.base@17.0.4.1/LinkedBlockingQueue.java:435)
        at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@17.0.4.1/ThreadPoolExecutor.java:1062)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@17.0.4.1/ThreadPoolExecutor.java:1122)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@17.0.4.1/ThreadPoolExecutor.java:635)
        at java.lang.Thread.run(java.base@17.0.4.1/Thread.java:833)

   Locked ownable synchronizers:
        - None

"Packet-Dispatcher-1" #23 prio=5 os_prio=0 cpu=15.63ms elapsed=88.94s tid=0x000001fe5389dce0 nid=0x6838 waiting on condition  [0x00000089a88fe000]
   java.lang.Thread.State: WAITING (parking)
        at jdk.internal.misc.Unsafe.park(java.base@17.0.4.1/Native Method)
        - parking to wait for  <0x00000000e07656c0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(java.base@17.0.4.1/LockSupport.java:341)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(java.base@17.0.4.1/AbstractQueuedSynchronizer.java:506)
        at java.util.concurrent.ForkJoinPool.unmanagedBlock(java.base@17.0.4.1/ForkJoinPool.java:3463)
        at java.util.concurrent.ForkJoinPool.managedBlock(java.base@17.0.4.1/ForkJoinPool.java:3434)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@17.0.4.1/AbstractQueuedSynchronizer.java:1623)
        at java.util.concurrent.LinkedBlockingQueue.take(java.base@17.0.4.1/LinkedBlockingQueue.java:435)
        at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@17.0.4.1/ThreadPoolExecutor.java:1062)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@17.0.4.1/ThreadPoolExecutor.java:1122)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@17.0.4.1/ThreadPoolExecutor.java:635)
        at java.lang.Thread.run(java.base@17.0.4.1/Thread.java:833)

   Locked ownable synchronizers:
        - None

"Packet-Dispatcher-2" #25 prio=5 os_prio=0 cpu=0.00ms elapsed=88.37s tid=0x000001fe53888b60 nid=0x59e4 waiting on condition  [0x00000089a77ff000]
   java.lang.Thread.State: WAITING (parking)
        at jdk.internal.misc.Unsafe.park(java.base@17.0.4.1/Native Method)
        - parking to wait for  <0x00000000e07656c0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(java.base@17.0.4.1/LockSupport.java:341)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(java.base@17.0.4.1/AbstractQueuedSynchronizer.java:506)
        at java.util.concurrent.ForkJoinPool.unmanagedBlock(java.base@17.0.4.1/ForkJoinPool.java:3463)
        at java.util.concurrent.ForkJoinPool.managedBlock(java.base@17.0.4.1/ForkJoinPool.java:3434)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@17.0.4.1/AbstractQueuedSynchronizer.java:1623)
        at java.util.concurrent.LinkedBlockingQueue.take(java.base@17.0.4.1/LinkedBlockingQueue.java:435)
        at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@17.0.4.1/ThreadPoolExecutor.java:1062)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@17.0.4.1/ThreadPoolExecutor.java:1122)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@17.0.4.1/ThreadPoolExecutor.java:635)
        at java.lang.Thread.run(java.base@17.0.4.1/Thread.java:833)

   Locked ownable synchronizers:
        - None

"DestroyJavaVM" #27 prio=5 os_prio=0 cpu=250.00ms elapsed=88.35s tid=0x000001fe538899d0 nid=0xc4 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Packet-Dispatcher-3" #55 prio=5 os_prio=0 cpu=31.25ms elapsed=86.47s tid=0x000001fe547318a0 nid=0x3d94 waiting on condition  [0x00000089a8bff000]
   java.lang.Thread.State: WAITING (parking)
        at jdk.internal.misc.Unsafe.park(java.base@17.0.4.1/Native Method)
        - parking to wait for  <0x00000000e07656c0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(java.base@17.0.4.1/LockSupport.java:341)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionNode.block(java.base@17.0.4.1/AbstractQueuedSynchronizer.java:506)
        at java.util.concurrent.ForkJoinPool.unmanagedBlock(java.base@17.0.4.1/ForkJoinPool.java:3463)
        at java.util.concurrent.ForkJoinPool.managedBlock(java.base@17.0.4.1/ForkJoinPool.java:3434)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@17.0.4.1/AbstractQueuedSynchronizer.java:1623)
        at java.util.concurrent.LinkedBlockingQueue.take(java.base@17.0.4.1/LinkedBlockingQueue.java:435)
        at java.util.concurrent.ThreadPoolExecutor.getTask(java.base@17.0.4.1/ThreadPoolExecutor.java:1062)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@17.0.4.1/ThreadPoolExecutor.java:1122)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@17.0.4.1/ThreadPoolExecutor.java:635)
        at java.lang.Thread.run(java.base@17.0.4.1/Thread.java:833)

   Locked ownable synchronizers:
        - None

The problem is that the netty threads aren't daemon threads and only shut down after System.exit but not after all threads created by the minestom server have exited normally. System.exit is a workaround

TheMeinerLP commented 1 year ago

I can confirm that. We(CloudNet Devs and ME) discussed already that on discord.