-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Describe the bug
A Quarkus application that uses an Emitter to send messages to a reactive messaging pipeline incidentally propagates context to the Incoming method. Of course, this only happens when the channel is "in-memory". When the channel uses a connector - for example, Kafka - then, as expected, propagation does not occur, because the context is lost when the message is sent to Kafka.
This creates a leaky abstraction with respect to context propagation in @Incoming methods. These methods unexpectedly inherit context from the Emitter's scope only when the channel uses an in-memory connector. I would expect an @Incoming method to never inherit context, so that its relationship to the current context is consistent regardless of the connector being used.
Expected behavior
The @Incoming method should execute with a cleared context regardless of whether it receives messages from an external system (e.g. Kafka) or an in-memory data structure.
Actual behavior
Context is propagated from the Quarkus REST resource to the Reactive Messaging consumer. This denies the Reactive Messaging consumer the ability to start its own request context to use while consume messages. For example, if the @Incoming method were also decorated with @ActivateRequestScope, then the method would use the request scope created by Quarkus REST, and that scope will be destroyed when Quarkus REST has finished serving the request.
How to Reproduce?
This small Quarkus application reproduces the issue. Its test passes, because it uses a ManagedExecutor to clear the context before calling the Emitter. This is a workaround to the described issue. Removing this workaround and instead executing the commented out code return emitter.send(body); (no ManagedExecutor used) demonstrates the problem.
@Path("/hello")
class GreetingResource {
@Channel("greeting")
Emitter<String> emitter;
@Inject
@ManagedExecutorConfig(maxAsync = 2, maxQueued = 3, cleared = CDI)
ManagedExecutor executor;
@POST
@Consumes(MediaType.TEXT_PLAIN)
public CompletionStage<Void> hello(String body) {
// context incidentally propagated, use ManagedExecutor to clear context at the emitter
// return emitter.send(body);
return CompletableFuture.supplyAsync(() -> emitter.send(body), executor).join();
}
}
@ApplicationScoped
class GreetingProcessor {
@Inject RequestContextController controller;
@Inject Logger logger;
@Incoming("greeting")
void process(String name) {
if (!controller.activate()) {
throw new IllegalStateException("Request context is already active");
}
logger.infof("Hello, %s", name);
}
}quarkus-emitter-new-request-context.zip
Output of uname -a or ver
Darwin MacBookPro 24.2.0 Darwin Kernel Version 24.2.0: Fri Dec 6 19:01:59 PST 2024; root:xnu-11215.61.5~2/RELEASE_ARM64_T6000 arm64
Output of java -version
openjdk version "21.0.6" 2025-01-21 LTS OpenJDK Runtime Environment Temurin-21.0.6+7 (build 21.0.6+7-LTS) OpenJDK 64-Bit Server VM Temurin-21.0.6+7 (build 21.0.6+7-LTS, mixed mode, sharing)
Quarkus version or git rev
3.18.3
Build tool (ie. output of mvnw --version or gradlew --version)
Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae) Maven home: /Users/jgilday/.m2/wrapper/dists/apache-maven-3.9.6-bin/3311e1d4/apache-maven-3.9.6 Java version: 21.0.6, vendor: Eclipse Adoptium, runtime: /Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home Default locale: en_US, platform encoding: UTF-8 OS name: "mac os x", version: "15.2", arch: "aarch64", family: "mac"
Additional information
No response