From b6ec152037d70a60f183d42315470ec1912ea5be Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Tue, 10 Jun 2025 21:06:30 +0900 Subject: [PATCH] fix server stuck on wait shutdown --- .../pufferfish/util/AsyncExecutor.java | 4 +-- .../dreeam/leaf/async/ShutdownExecutors.java | 33 +++++++++++++++---- .../dreeam/leaf/async/ai/AsyncGoalThread.java | 4 +-- .../leaf/async/path/AsyncPathProcessor.java | 2 +- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/leaf-server/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java b/leaf-server/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java index e417ef8d..2b57a863 100644 --- a/leaf-server/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java +++ b/leaf-server/src/main/java/gg/pufferfish/pufferfish/util/AsyncExecutor.java @@ -28,10 +28,10 @@ public class AsyncExecutor implements Runnable { thread.start(); } - public void kill() throws InterruptedException { + public void join(long millis) throws InterruptedException { killswitch = true; LockSupport.unpark(thread); - thread.join(); + thread.join(millis); } public void submit(Runnable runnable) { diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/ShutdownExecutors.java b/leaf-server/src/main/java/org/dreeam/leaf/async/ShutdownExecutors.java index ee6d490d..b3d1f658 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/ShutdownExecutors.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/ShutdownExecutors.java @@ -1,37 +1,58 @@ package org.dreeam.leaf.async; import net.minecraft.server.MinecraftServer; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dreeam.leaf.async.ai.AsyncGoalThread; +import org.dreeam.leaf.async.path.AsyncPathProcessor; import org.dreeam.leaf.async.tracker.MultithreadedTracker; -public class ShutdownExecutors { - public static void shutdown(MinecraftServer server) { +import java.util.concurrent.TimeUnit; +public class ShutdownExecutors { + public static final Logger LOGGER = LogManager.getLogger("Leaf"); + + public static void shutdown(MinecraftServer server) { if (server.mobSpawnExecutor != null) { + LOGGER.info("Waiting for mob spawning thread to shutdown..."); try { - server.mobSpawnExecutor.kill(); + server.mobSpawnExecutor.join(3000L); } catch (InterruptedException ignored) { } } if (AsyncPlayerDataSaving.IO_POOL != null) { + LOGGER.info("Waiting for player I/O executor to shutdown..."); AsyncPlayerDataSaving.IO_POOL.shutdown(); try { - AsyncPlayerDataSaving.IO_POOL.awaitTermination(300L, java.util.concurrent.TimeUnit.SECONDS); + AsyncPlayerDataSaving.IO_POOL.awaitTermination(60L, TimeUnit.SECONDS); } catch (InterruptedException ignored) { } } if (server.asyncGoalThread != null) { + LOGGER.info("Waiting for mob target finding thread to shutdown..."); + AsyncGoalThread.RUNNING = false; try { - server.asyncGoalThread.join(); + server.asyncGoalThread.join(3000L); } catch (InterruptedException ignored) { } } if (MultithreadedTracker.TRACKER_EXECUTOR != null) { + LOGGER.info("Waiting for mob tracker executor to shutdown..."); MultithreadedTracker.TRACKER_EXECUTOR.shutdown(); try { - MultithreadedTracker.TRACKER_EXECUTOR.awaitTermination(10L, java.util.concurrent.TimeUnit.SECONDS); + MultithreadedTracker.TRACKER_EXECUTOR.awaitTermination(10L, TimeUnit.SECONDS); + } catch (InterruptedException ignored) { + } + } + + if (AsyncPathProcessor.pathProcessingExecutor != null) { + LOGGER.info("Waiting for mob pathfinding executor to shutdown..."); + AsyncPathProcessor.pathProcessingExecutor.shutdown(); + try { + AsyncPathProcessor.pathProcessingExecutor.awaitTermination(10L, TimeUnit.SECONDS); } catch (InterruptedException ignored) { } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java index 06bd5e48..2d91d2c3 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java @@ -8,7 +8,7 @@ import java.util.OptionalInt; import java.util.concurrent.locks.LockSupport; public class AsyncGoalThread extends Thread { - + public static volatile boolean RUNNING = true; public AsyncGoalThread(final MinecraftServer server) { super(() -> run(server), "Leaf Async Goal Thread"); this.setDaemon(false); @@ -18,7 +18,7 @@ public class AsyncGoalThread extends Thread { } private static void run(MinecraftServer server) { - while (server.isRunning()) { + while (RUNNING) { boolean retry = false; for (ServerLevel level : server.getAllLevels()) { var exec = level.asyncGoalExecutor; diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/path/AsyncPathProcessor.java b/leaf-server/src/main/java/org/dreeam/leaf/async/path/AsyncPathProcessor.java index 7ebcec15..3fac5839 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/path/AsyncPathProcessor.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/path/AsyncPathProcessor.java @@ -28,7 +28,7 @@ public class AsyncPathProcessor { private static final String THREAD_PREFIX = "Leaf Async Pathfinding"; private static final Logger LOGGER = LogManager.getLogger(THREAD_PREFIX); private static long lastWarnMillis = System.currentTimeMillis(); - private static final ThreadPoolExecutor pathProcessingExecutor = new ThreadPoolExecutor( + public static final ThreadPoolExecutor pathProcessingExecutor = new ThreadPoolExecutor( 1, AsyncPathfinding.asyncPathfindingMaxThreads, AsyncPathfinding.asyncPathfindingKeepalive, TimeUnit.SECONDS,