From 082f89190ca756c9753190844de08a934a344fb8 Mon Sep 17 00:00:00 2001 From: JRoy <10731363+JRoy@users.noreply.github.com> Date: Sun, 14 Jun 2026 10:18:20 -0700 Subject: [PATCH] Shutdown executors on disable Closes #6446 --- .../com/earth2me/essentials/Essentials.java | 3 ++ .../java/com/earth2me/essentials/I18n.java | 28 +++++++++++++++++-- .../earth2me/essentials/utils/PasteUtil.java | 27 ++++++++++++++++-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java index 5170a694a63..798b264a34d 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java @@ -46,6 +46,7 @@ import com.earth2me.essentials.updatecheck.UpdateChecker; import com.earth2me.essentials.userstorage.ModernUserMap; import com.earth2me.essentials.utils.FormatUtil; +import com.earth2me.essentials.utils.PasteUtil; import com.earth2me.essentials.utils.VersionUtil; import io.papermc.lib.PaperLib; import net.ess3.api.Economy; @@ -587,6 +588,8 @@ public void onDisable() { getUsers().shutdown(); EssentialsConfiguration.shutdownExecutor(); + PasteUtil.shutdownExecutor(); + getServer().getScheduler().cancelTasks(this); HandlerList.unregisterAll(this); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/I18n.java b/Essentials/src/main/java/com/earth2me/essentials/I18n.java index c7ae82eaada..928bc06a7c8 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/I18n.java +++ b/Essentials/src/main/java/com/earth2me/essentials/I18n.java @@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.logging.Level; import java.util.regex.Pattern; @@ -35,7 +36,7 @@ public class I18n implements net.ess3.api.II18n { private static final String MESSAGES = "messages"; private static final Pattern NODOUBLEMARK = Pattern.compile("''"); - private static final ExecutorService BUNDLE_LOADER_EXECUTOR = Executors.newFixedThreadPool(2); + private static volatile ExecutorService BUNDLE_LOADER_EXECUTOR = Executors.newFixedThreadPool(2); private static final ResourceBundle NULL_BUNDLE = new ResourceBundle() { @SuppressWarnings("NullableProblems") public Enumeration getKeys() { @@ -106,6 +107,29 @@ public void onEnable() { public void onDisable() { instance = null; + shutdownExecutor(); + } + + private static synchronized ExecutorService getExecutor() { + if (BUNDLE_LOADER_EXECUTOR == null || BUNDLE_LOADER_EXECUTOR.isShutdown() || BUNDLE_LOADER_EXECUTOR.isTerminated()) { + BUNDLE_LOADER_EXECUTOR = Executors.newFixedThreadPool(2); + } + return BUNDLE_LOADER_EXECUTOR; + } + + private static synchronized void shutdownExecutor() { + final ExecutorService exec = BUNDLE_LOADER_EXECUTOR; + if (exec == null) { + return; + } + exec.shutdown(); + try { + if (!exec.awaitTermination(5, TimeUnit.SECONDS)) { + exec.shutdownNow(); + } + } catch (final InterruptedException ignored) { + exec.shutdownNow(); + } } @Override @@ -124,7 +148,7 @@ private ResourceBundle getBundle(final Locale locale) { synchronized (loadingBundles) { if (!loadingBundles.contains(locale)) { loadingBundles.add(locale); - BUNDLE_LOADER_EXECUTOR.submit(() -> { + getExecutor().submit(() -> { blockingLoadBundle(locale); synchronized (loadingBundles) { loadingBundles.remove(locale); diff --git a/Essentials/src/main/java/com/earth2me/essentials/utils/PasteUtil.java b/Essentials/src/main/java/com/earth2me/essentials/utils/PasteUtil.java index a6f0f1ba6ef..2118d47b76c 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/utils/PasteUtil.java +++ b/Essentials/src/main/java/com/earth2me/essentials/utils/PasteUtil.java @@ -16,12 +16,13 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.zip.GZIPOutputStream; public final class PasteUtil { private static final String PASTE_URL = "https://pastes.dev/"; private static final String PASTE_UPLOAD_URL = "https://api.pastes.dev/post"; - private static final ExecutorService PASTE_EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); + private static volatile ExecutorService PASTE_EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); private static final Gson GSON = new Gson(); private PasteUtil() { @@ -35,7 +36,7 @@ private PasteUtil() { */ public static CompletableFuture createPaste(List pages) { final CompletableFuture future = new CompletableFuture<>(); - PASTE_EXECUTOR_SERVICE.submit(() -> { + getExecutor().submit(() -> { try { final HttpURLConnection connection = (HttpURLConnection) new URL(PASTE_UPLOAD_URL).openConnection(); connection.setRequestMethod("POST"); @@ -81,6 +82,28 @@ public static CompletableFuture createPaste(List pages) return future; } + private static synchronized ExecutorService getExecutor() { + if (PASTE_EXECUTOR_SERVICE == null || PASTE_EXECUTOR_SERVICE.isShutdown() || PASTE_EXECUTOR_SERVICE.isTerminated()) { + PASTE_EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); + } + return PASTE_EXECUTOR_SERVICE; + } + + public static synchronized void shutdownExecutor() { + final ExecutorService exec = PASTE_EXECUTOR_SERVICE; + if (exec == null) { + return; + } + exec.shutdown(); + try { + if (!exec.awaitTermination(5, TimeUnit.SECONDS)) { + exec.shutdownNow(); + } + } catch (final InterruptedException ignored) { + exec.shutdownNow(); + } + } + public static class PasteFile { private final String name; private final String contents;