From 08ba1d14ea05421c496ea33ee9359d8269f1cef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20=C3=89pardaud?= Date: Wed, 10 Apr 2024 15:13:31 +0200 Subject: [PATCH] CP: set up a temporary no-context/no-executor ContextManagerProvider during boot Because some extensions (only known one is spring-cloud-config-client) use Vert.x via Mutiny before runtime init is done. Mutiny and CP are both not set up yet, due to missing executor, but I'm starting CP with zero contexts and an executor which throws with an explicit error message, which should be enough to boot until runtime is properly set up. --- .../SmallRyeContextPropagationRecorder.java | 105 +++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/extensions/smallrye-context-propagation/runtime/src/main/java/io/quarkus/smallrye/context/runtime/SmallRyeContextPropagationRecorder.java b/extensions/smallrye-context-propagation/runtime/src/main/java/io/quarkus/smallrye/context/runtime/SmallRyeContextPropagationRecorder.java index 93a2d0d3cbc37..4955a2bbf54b7 100644 --- a/extensions/smallrye-context-propagation/runtime/src/main/java/io/quarkus/smallrye/context/runtime/SmallRyeContextPropagationRecorder.java +++ b/extensions/smallrye-context-propagation/runtime/src/main/java/io/quarkus/smallrye/context/runtime/SmallRyeContextPropagationRecorder.java @@ -1,11 +1,18 @@ package io.quarkus.smallrye.context.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 java.util.function.Supplier; import org.eclipse.microprofile.context.ManagedExecutor; import org.eclipse.microprofile.context.ThreadContext; +import org.eclipse.microprofile.context.spi.ContextManager.Builder; import org.eclipse.microprofile.context.spi.ContextManagerExtension; import org.eclipse.microprofile.context.spi.ContextManagerProvider; import org.eclipse.microprofile.context.spi.ThreadContextProvider; @@ -23,6 +30,92 @@ @Recorder public class SmallRyeContextPropagationRecorder { + private static final ExecutorService NOPE_EXECUTOR_SERVICE = new ExecutorService() { + + @Override + public void execute(Runnable command) { + nope(); + } + + @Override + public void shutdown() { + nope(); + } + + @Override + public List shutdownNow() { + nope(); + return null; + } + + @Override + public boolean isShutdown() { + nope(); + return false; + } + + @Override + public boolean isTerminated() { + nope(); + return false; + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + nope(); + return false; + } + + @Override + public Future submit(Callable task) { + nope(); + return null; + } + + @Override + public Future submit(Runnable task, T result) { + nope(); + return null; + } + + @Override + public Future submit(Runnable task) { + nope(); + return null; + } + + @Override + public List> invokeAll(Collection> tasks) throws InterruptedException { + nope(); + return null; + } + + @Override + public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) + throws InterruptedException { + nope(); + return null; + } + + @Override + public T invokeAny(Collection> tasks) + throws InterruptedException, ExecutionException { + nope(); + return null; + } + + @Override + public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + nope(); + return null; + } + + private void nope() { + throw new RuntimeException( + "Trying to invoke ContextPropagation on a partially-configured ContextManager instance. You should wait until runtime init is done. You can do that by consuming the ContextPropagationBuildItem."); + } + }; private static SmallRyeContextManager.Builder builder; public void configureStaticInit(List discoveredProviders, @@ -39,6 +132,16 @@ public void configureStaticInit(List discoveredProviders, .getContextManagerBuilder(); builder.withThreadContextProviders(discoveredProviders.toArray(new ThreadContextProvider[0])); builder.withContextManagerExtensions(discoveredExtensions.toArray(new ContextManagerExtension[0])); + + // During boot, if anyone is using CP, they will get no propagation and an error if they try to use + // the executor. This is (so far) only for spring-cloud-config-client which uses Vert.x via Mutiny + // to load config before we're ready for runtime init + SmallRyeContextManager.Builder noContextBuilder = (SmallRyeContextManager.Builder) ContextManagerProvider.instance() + .getContextManagerBuilder(); + noContextBuilder.withThreadContextProviders(new ThreadContextProvider[0]); + noContextBuilder.withContextManagerExtensions(new ContextManagerExtension[0]); + noContextBuilder.withDefaultExecutorService(NOPE_EXECUTOR_SERVICE); + ContextManagerProvider.instance().registerContextManager(noContextBuilder.build(), null /* not used */); } public void configureRuntime(ExecutorService executorService, ShutdownContext shutdownContext) { @@ -58,7 +161,7 @@ public void run() { } }); //Avoid leaking the classloader: - this.builder = null; + SmallRyeContextPropagationRecorder.builder = null; } public Supplier initializeManagedExecutor(ExecutorService executorService) {