You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by da...@apache.org on 2025/11/24 06:36:04 UTC
(jackrabbit-oak) 01/01: OAK-11916 : added exiting executor service in oak-commons
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 <ri...@gmail.com>
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