Skip to content

Commit

Permalink
CP: set up a temporary no-context/no-executor ContextManagerProvider …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
FroMage committed Apr 10, 2024
1 parent b9cc3c2 commit 08ba1d1
Showing 1 changed file with 104 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<Runnable> 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 <T> Future<T> submit(Callable<T> task) {
nope();
return null;
}

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

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

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

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

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

@Override
public <T> T invokeAny(Collection<? extends Callable<T>> 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<ThreadContextProvider> discoveredProviders,
Expand All @@ -39,6 +132,16 @@ public void configureStaticInit(List<ThreadContextProvider> 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) {
Expand All @@ -58,7 +161,7 @@ public void run() {
}
});
//Avoid leaking the classloader:
this.builder = null;
SmallRyeContextPropagationRecorder.builder = null;
}

public Supplier<Object> initializeManagedExecutor(ExecutorService executorService) {
Expand Down

0 comments on commit 08ba1d1

Please sign in to comment.