I'm trying to get context propagation working in Quarkus native mode.
The code below works as expected in the JVM mode, but returns MDC value: null
in the native mode.
By "as expected" I mean:
Response to curl http://localhost:8080/thread-context
is MDC value: from-thread-context
@Inject
ManagedExecutor managedExecutor;
@Inject
ThreadContext threadContext;
private final Supplier<String> mdcValueSupplier =
() -> "MDC value: " + MDC.get("foo") + "\n";
@GET
@Path("thread-context")
public String get() throws ExecutionException, InterruptedException {
MDC.put("foo", "from-thread-context");
Supplier<String> ctxSupplier = threadContext.contextualSupplier(mdcValueSupplier);
return managedExecutor.supplyAsync(ctxSupplier).get();
}
I've created a github repo with full code of demo app and step-by-step instruction to reproduce the issue.
Dependency io.quarkus:quarkus-smallrye-context-propagation
is present.
Quarkus version: 1.9.2
Q: Is it the issue with my code, or with Quarkus?
For the reference: Quarkus documentatin on context propagation
Your code is essentially fine [1], and Quarkus is also fine for that matter -- but there are two things to understand.
One, you're not doing any kind of "manual context propagation". Your code works by accident, because Quarkus uses JBoss LogManager as the logger, and its MDC isn't an ordinary
ThreadLocal
, it's anInheritableThreadLocal
. So it kinda sorta sometimes propagates the context itself. But that's nothing to rely on. If you for example do a live reload (by modifying the code a bit and runningcurl
again), it will stop working in JVM mode too.Two, the very point of context propagation is to transfer thread-local state from one thread to another, but that doesn't happen automagically. Either you do that yourself (that would be "manual context propagation"), by calling the respective APIs, or you can implement a
ThreadContextProvider
.I took a brief look at the MDC API (http://www.slf4j.org/api/org/slf4j/MDC.html) and it seems rudimentary context propagation can be implemented with
getCopyOfContextMap
andsetContextMap
. Here's an implementation I put together quickly -- beware, I didn't test the code too much:If you create a
META-INF/services/org.eclipse.microprofile.context.spi.ThreadContextProvider
file containing the fully qualified name of this class, then MDC propagation should work for you, even in native.One possible issue with this is that whatever changes you do to
MDC
on the new thread will not be propagated back to the original thread, because SLF4J intentionally doesn't provide access to the backing map, it only hands out copies. That might be OK for you, or not.[1] You don't have to "contextualize" your
Supplier
byThreadContext.contextualSupplier
if you submit it toManagedExecutor
-- theManagedExecutor
does that automatically.