Skip to content

Commit

Permalink
Vertx: use NoopShutdownExecutorService in the prod mode
Browse files Browse the repository at this point in the history
- in the prod mode we wrap the ExecutorService and the shutdown() and
shutdownNow() are deliberately not delegated
- this is a workaround to solve the problem described in
#16833 (comment)
- the Vertx instance is closed before
io.quarkus.runtime.ExecutorRecorder.createShutdownTask() is used
- and when it's closed the underlying worker thread pool (which is in
the prod mode backed by the ExecutorBuildItem) is closed as well
- as a result the quarkus.thread-pool.shutdown-interrupt config property
and logic defined in ExecutorRecorder.createShutdownTask() is completely
ignored
  • Loading branch information
mkouba committed Jan 30, 2024
1 parent ffec931 commit d7f8de4
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package io.quarkus.vertx.core.runtime;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.jboss.logging.Logger;

class NoopShutdownExecutorService implements ExecutorService {

private static final Logger LOG = Logger.getLogger(NoopShutdownExecutorService.class);

private final ExecutorService delegate;

NoopShutdownExecutorService(ExecutorService delegate) {
this.delegate = delegate;
}

@Override
public void execute(Runnable command) {
delegate.execute(command);
}

@Override
public void shutdown() {
LOG.debugf("shutdown() deliberately not delegated");
}

@Override
public List<Runnable> shutdownNow() {
LOG.debugf("shutdownNow() deliberately not delegated");
return List.of();
}

@Override
public boolean isShutdown() {
return delegate.isShutdown();
}

@Override
public boolean isTerminated() {
return delegate.isTerminated();
}

@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return delegate.awaitTermination(timeout, unit);
}

@Override
public <T> Future<T> submit(Callable<T> task) {
return delegate.submit(task);
}

@Override
public <T> Future<T> submit(Runnable task, T result) {
return delegate.submit(task, result);
}

@Override
public Future<?> submit(Runnable task) {
return delegate.submit(task);
}

@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
return delegate.invokeAll(tasks);
}

@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException {
return delegate.invokeAll(tasks, timeout, unit);
}

@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
return delegate.invokeAny(tasks);
}

@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return delegate.invokeAny(tasks, timeout, unit);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,16 @@ public class VertxCoreRecorder {
public Supplier<Vertx> configureVertx(VertxConfiguration config, ThreadPoolConfig threadPoolConfig,
LaunchMode launchMode, ShutdownContext shutdown, List<Consumer<VertxOptions>> customizers,
ExecutorService executorProxy) {
QuarkusExecutorFactory.sharedExecutor = executorProxy;
if (launchMode == LaunchMode.NORMAL) {
// In the prod mode we wrap the ExecutorService and the shutdown() and shutdownNow() are deliberately not delegated
// This is a workaround to solve the problem described in https://github.com/quarkusio/quarkus/issues/16833#issuecomment-1917042589
// The Vertx instance is closed before io.quarkus.runtime.ExecutorRecorder.createShutdownTask() is used
// And when it's closed the underlying worker thread pool (which is in the prod mode backed by the ExecutorBuildItem) is closed as well
// As a result the quarkus.thread-pool.shutdown-interrupt config property and logic defined in ExecutorRecorder.createShutdownTask() is completely ignored
QuarkusExecutorFactory.sharedExecutor = new NoopShutdownExecutorService(executorProxy);
} else {
QuarkusExecutorFactory.sharedExecutor = executorProxy;
}
if (launchMode != LaunchMode.DEVELOPMENT) {
vertx = new VertxSupplier(launchMode, config, customizers, threadPoolConfig, shutdown);
// we need this to be part of the last shutdown tasks because closing it early (basically before Arc)
Expand Down

0 comments on commit d7f8de4

Please sign in to comment.