This is an automated email from the ASF dual-hosted git repository.
daim pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new 2c9dc7a84b OAK-11916 : added exiting executor service in oak-commons
(#2622)
2c9dc7a84b is described below
commit 2c9dc7a84ba6564b636bd81888d3a6bf44ccdeb9
Author: Rishabh Kumar <[email protected]>
AuthorDate: Mon Nov 24 20:57:59 2025 +0530
OAK-11916 : added exiting executor service in oak-commons (#2622)
* OAK-11916 : added exiting executor service in oak-commons
* OAK-11916 : updated package version
* OAK-11916 : fixed failing issues due to wrong guava import
---
.../commons/internal/concurrent/ExecutorUtils.java | 30 ++++++++++++++++++++++
.../commons/internal/concurrent/package-info.java | 2 +-
.../internal/concurrent/ExecutorUtilsTest.java | 28 ++++++++++++++++++++
3 files changed, 59 insertions(+), 1 deletion(-)
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..9abfde3393 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
@@ -21,6 +21,13 @@ package
org.apache.jackrabbit.oak.commons.internal.concurrent;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
+import org.apache.jackrabbit.guava.common.util.concurrent.ThreadFactoryBuilder;
+import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
+
+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 +43,27 @@ 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);
+ return service;
+
+ }
+
+ private static void addRuntimeShutdownHook(final ExecutorService executor)
{
+ Runtime.getRuntime().addShutdownHook(
+ new Thread(() -> new ExecutorCloser(executor, 120,
TimeUnit.SECONDS).close(),
+ "RuntimeShutdownHook-for-" + executor));
+ }
+
+ private static void setDeamonThreadFactory(final ThreadPoolExecutor
executor) {
+ executor.setThreadFactory(
+ new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setThreadFactory(executor.getThreadFactory())
+ .build());
+ }
}
diff --git
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/package-info.java
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/package-info.java
index 1d60571596..26de19423a 100644
---
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/package-info.java
+++
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/package-info.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-@Version("1.1.0")
+@Version("1.2.0")
@Internal(since = "1.0.0")
package org.apache.jackrabbit.oak.commons.internal.concurrent;
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