This is an automated email from the ASF dual-hosted git repository. daim pushed a commit to branch OAK-11916 in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 789a893121c5fa29310742a65e008c117d2a50ab Author: rishabhdaim <[email protected]> AuthorDate: Mon Nov 24 12:05:46 2025 +0530 OAK-11916 : added exiting executor service in oak-commons --- .../commons/internal/concurrent/ExecutorUtils.java | 36 ++++++++++++++++++++++ .../internal/concurrent/ExecutorUtilsTest.java | 28 +++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/ExecutorUtils.java b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/ExecutorUtils.java index 4ef9de91e1..d6392b5f18 100644 --- a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/ExecutorUtils.java +++ b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/ExecutorUtils.java @@ -20,6 +20,11 @@ package org.apache.jackrabbit.oak.commons.internal.concurrent; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * Util methods for {@link java.util.concurrent.Executor} @@ -36,4 +41,35 @@ public class ExecutorUtils { public static ExecutorService newDirectExecutorService() { return new DirectExecutorService(); } + + public static ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) { + setDeamonThreadFactory(executor); + final ExecutorService service = Executors.unconfigurableExecutorService(executor); + // JVM shutdown hook for graceful executor shutdown + addRuntimeShutdownHook(executor, service); + return service; + + } + + private static void addRuntimeShutdownHook(ThreadPoolExecutor executor, ExecutorService service) { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + executor.shutdown(); + try { + if (!executor.awaitTermination(120, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + }, "RuntimeShutdownHook-for-" + service)); + } + + private static void setDeamonThreadFactory(final ThreadPoolExecutor executor) { + executor.setThreadFactory( + new ThreadFactoryBuilder() + .setDaemon(true) + .setThreadFactory(executor.getThreadFactory()) + .build()); + } } diff --git a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/internal/concurrent/ExecutorUtilsTest.java b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/internal/concurrent/ExecutorUtilsTest.java index 20b9c81b83..d7d55465a9 100644 --- a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/internal/concurrent/ExecutorUtilsTest.java +++ b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/internal/concurrent/ExecutorUtilsTest.java @@ -23,7 +23,10 @@ import org.junit.Test; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * Unit cases for ExecutorUtils @@ -72,4 +75,29 @@ public class ExecutorUtilsTest { Assert.assertEquals("test", future.get()); } + @Test + public void testGetExitingExecutorServiceReturnsUnconfigurableExecutor() { + ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1); + ExecutorService service = ExecutorUtils.getExitingExecutorService(executor); + Assert.assertNotNull(service); + Assert.assertFalse(service.getClass().getName().contains("ThreadPoolExecutor")); + } + + @Test + public void testDaemonThreadFactoryIsSet() { + ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1); + ExecutorUtils.getExitingExecutorService(executor); + Assert.assertTrue(executor.getThreadFactory().newThread(() -> {}).isDaemon()); + } + + @Test + public void testShutdownHookIsRegisteredAndShutsDownExecutor() throws Exception { + ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1); + ExecutorUtils.getExitingExecutorService(executor); + // Simulate JVM shutdown hook + executor.shutdown(); + boolean terminated = executor.awaitTermination(1, TimeUnit.SECONDS); + Assert.assertTrue(terminated || executor.isShutdown()); + } + } \ No newline at end of file
