Skip to content

Commit

Permalink
Implement uncaught exception handler for VT executor
Browse files Browse the repository at this point in the history
  • Loading branch information
ozangunalp committed Oct 6, 2023
1 parent 05de6e5 commit 58f1cdf
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
Expand Down Expand Up @@ -107,34 +106,27 @@ static ExecutorService newVirtualThreadPerTaskExecutorWithName(String prefix)
Method ofVirtual = Thread.class.getMethod("ofVirtual");
Object vtb = ofVirtual.invoke(VirtualThreadsRecorder.class);
Class<?> vtbClass = Class.forName("java.lang.Thread$Builder$OfVirtual");
Method name = vtbClass.getMethod("name", String.class, long.class);
vtb = name.invoke(vtb, prefix, 0);
// .name()
if (prefix != null) {
Method name = vtbClass.getMethod("name", String.class, long.class);
vtb = name.invoke(vtb, prefix, 0);
}
// .uncaughtExceptionHandler()
Method uncaughtHandler = vtbClass.getMethod("uncaughtExceptionHandler", Thread.UncaughtExceptionHandler.class);
vtb = uncaughtHandler.invoke(vtb, new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
logger.errorf(e, "Thread %s threw an uncaught exception:", t);
}
});
// .factory()
Method factory = vtbClass.getMethod("factory");
ThreadFactory tf = (ThreadFactory) factory.invoke(vtb);

return (ExecutorService) Executors.class.getMethod("newThreadPerTaskExecutor", ThreadFactory.class)
.invoke(VirtualThreadsRecorder.class, tf);
}

static ExecutorService newVirtualThreadPerTaskExecutor()
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
return (ExecutorService) Executors.class.getMethod("newVirtualThreadPerTaskExecutor")
.invoke(VirtualThreadsRecorder.class);
}

static ExecutorService newVirtualThreadExecutor()
throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
try {
Optional<String> namePrefix = config.namePrefix;
return namePrefix.isPresent() ? newVirtualThreadPerTaskExecutorWithName(namePrefix.get())
: newVirtualThreadPerTaskExecutor();
} catch (ClassNotFoundException e) {
logger.warn("Unable to invoke java.util.concurrent.Executors#newThreadPerTaskExecutor" +
" with VirtualThreadFactory, falling back to unnamed virtual threads", e);
return newVirtualThreadPerTaskExecutor();
}
}

/**
* This method uses reflection in order to allow developers to quickly test quarkus-loom without needing to
* change --release, --source, --target flags and to enable previews.
Expand All @@ -144,8 +136,9 @@ static ExecutorService newVirtualThreadExecutor()
private static ExecutorService createExecutor() {
if (config.enabled) {
try {
return new ContextPreservingExecutorService(newVirtualThreadExecutor());
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
String prefix = config.namePrefix.orElse(null);
return new ContextPreservingExecutorService(newVirtualThreadPerTaskExecutorWithName(prefix));
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException | ClassNotFoundException e) {
logger.debug("Unable to invoke java.util.concurrent.Executors#newVirtualThreadPerTaskExecutor", e);
//quite ugly but works
logger.warn("You weren't able to create an executor that spawns virtual threads, the default" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ void virtualThreadCustomScheduler()

@Test
@EnabledForJreRange(min = JRE.JAVA_20, disabledReason = "Virtual Threads are a preview feature starting from Java 20")
void execute() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
Executor executor = VirtualThreadsRecorder.newVirtualThreadPerTaskExecutor();
void execute() throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
Executor executor = VirtualThreadsRecorder.newVirtualThreadPerTaskExecutorWithName(null);
var assertSubscriber = Uni.createFrom().emitter(e -> {
assertThat(Thread.currentThread().getName()).isEmpty();
assertThatItRunsOnVirtualThread();
Expand Down

0 comments on commit 58f1cdf

Please sign in to comment.