Skip to content

Commit d17370b

Browse files
rnorthclaude
andcommitted
Make Timeouts executor lazily initialized and re-creatable
Replace the static final ExecutorService with a lazily-created one so that shutdown() doesn't permanently break subsequent container operations. The executor is re-created transparently on next use. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d506b0c commit d17370b

1 file changed

Lines changed: 20 additions & 12 deletions

File tree

  • core/src/main/java/org/testcontainers/utility/ducttape

core/src/main/java/org/testcontainers/utility/ducttape/Timeouts.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,28 @@
99
*/
1010
public class Timeouts {
1111

12-
private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool(new ThreadFactory() {
12+
private static final AtomicInteger THREAD_COUNTER = new AtomicInteger(0);
1313

14-
final AtomicInteger threadCounter = new AtomicInteger(0);
14+
private static final ThreadFactory THREAD_FACTORY = r -> {
15+
Thread thread = new Thread(r, "ducttape-" + THREAD_COUNTER.getAndIncrement());
16+
thread.setDaemon(true);
17+
return thread;
18+
};
1519

16-
@Override
17-
public Thread newThread(Runnable r) {
18-
Thread thread = new Thread(r, "ducttape-" + threadCounter.getAndIncrement());
19-
thread.setDaemon(true);
20-
return thread;
20+
private static volatile ExecutorService executorService;
21+
22+
private static synchronized ExecutorService getExecutorService() {
23+
if (executorService == null || executorService.isShutdown()) {
24+
executorService = Executors.newCachedThreadPool(THREAD_FACTORY);
2125
}
22-
});
26+
return executorService;
27+
}
2328

24-
public static void shutdown() {
25-
EXECUTOR_SERVICE.shutdown();
29+
public static synchronized void shutdown() {
30+
if (executorService != null) {
31+
executorService.shutdown();
32+
executorService = null;
33+
}
2634
}
2735

2836
/**
@@ -40,7 +48,7 @@ public static <T> T getWithTimeout(final int timeout, final TimeUnit timeUnit, f
4048

4149
check("timeout must be greater than zero", timeout > 0);
4250

43-
Future<T> future = EXECUTOR_SERVICE.submit(lambda);
51+
Future<T> future = getExecutorService().submit(lambda);
4452
return callFuture(timeout, timeUnit, future);
4553
}
4654

@@ -57,7 +65,7 @@ public static void doWithTimeout(final int timeout, final TimeUnit timeUnit, fin
5765

5866
check("timeout must be greater than zero", timeout > 0);
5967

60-
Future<?> future = EXECUTOR_SERVICE.submit(lambda);
68+
Future<?> future = getExecutorService().submit(lambda);
6169
callFuture(timeout, timeUnit, future);
6270
}
6371

0 commit comments

Comments
 (0)