On Thu, 26 Mar 2026 at 17:02, Ladislav Thon <lad...@gmail.com> wrote:Without responding to the rest of this thread, I would like to highlight that our Mutiny + context propagation integration is wrong, because it captures contexts at the time the `Uni`/`Multi` is created, which may very well happen (and relatively often does happen) outside of the actual request handler. Naively, contexts should be captured at the moment the `Uni`/`Multi` is subscribed to, but that typically happens in a framework, so again outside of the actual request handler. I might have some ideas for other context propagation issues, but for this one, I don't even have an idea.I disagree with this. It was meant to capture the context that is in the lexical scope of the lambda that captures it, precisely like lambdas capture variables from their lexical scopes, which is what is intuitive, and happens to be correct in both the request and session context cases.Now, it is incorrect in the case of at least tracing, which changes contexts in ways that are not lexical, and probably other types of contexts. But I don't think that's a problem here for these contexts.
--
You received this message because you are subscribed to the Google Groups "Quarkus Development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to quarkus-dev...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/quarkus-dev/CALbocOkvBERUoaEORB_SPCobvhVyeZo_f%2BaEdsJxBXjFPPXPWA%40mail.gmail.com.
In my opinion, this sort of context definition that you have of contexts being dynamic scopes depends on the context we're talking about.To me, at least the request and transaction contexts are definitely lexical, exactly like variables. Take this example:Uni<Void> m(Request r, Transaction t) {// here I'm using the request and transaction from the lexical scopedoSomething(r, t);// here I'm returning a Uni that captures the lexical contexts and does something with themreturn Uni.createFrom().item(() -> doSomething(r, t));}Now, this works because I know my lambda captured the lexical scope and I can still access the same request and transaction as the method. MP-CP was created, so that the same intuition as to "what the hell is the current context being captured here?" can be taken from the lexical scope of variables:Uni<Void> m() {// here I'm using the request and transaction from the lexical "implicit" scopedoSomething(CDI.currentContext(), Transaction.current());// here I'm returning a Uni that captures the lexical contexts and does something with themreturn Uni.createFrom().item(() -> doSomething(CDI.currentContext(), Transaction.current()));}
Nobody in their right mind would expect that, given context propagation, the request or transaction scopes in use within that last example in the Uni lambda, would be different from the ones active at the time of the m() method call. If you switch those contexts at subscription time, people will get very confused. Now, perhaps you're not suggesting that, and merely that you would capture the contexts in place at the Uni creation, and pass them on to the Uni from the starting point of the subscription, so in practice, both ways of looking at things end up executing equally.
But my intuition, and the design of MP-CP, is so that contexts are captured lexically, at lambda creation time, so that their contexts are the same as the outer scope of the lambda.
Again, this doesn't work for things like tracing, I suppose, because perhaps in this case, the contexts should be dynamic and not lexical.
This example can also look like this:```java@TransactionalUni<Void> foo() {return bar();}Uni<Void> bar() {return baz();}Uni<Void> baz() {return Uni.createFrom().item(() -> doSomething(CDI.currentContext(), Transaction.current()));}```The methods can be in different classes, possibly in different libraries. This is dynamic scoping at its purest.
Some might say that vast majority of `Uni`s and `Multi`s are created at the very place they are subscribed to (or not far -- subscriptions typically happens in the framework that called the application method that created the `Uni`/`Multi`), so there's no difference, but that's just ignoring the problem. At the very least, SmallRye Reactive Messaging creates all streams at application startup, which is very far from when the message handlers are called. If you use a hot publisher, you're typically also creating it far from the use site. I know SmallRye Health creates a `Uni` once and reuses it multiple times, again far from the creation site. (Far in time, not necessarily in space.) These usages might be a minority, but they are not insignificant, and they all cause troubles with context propagation.
--
Some might say that vast majority of `Uni`s and `Multi`s are created at the very place they are subscribed to (or not far -- subscriptions typically happens in the framework that called the application method that created the `Uni`/`Multi`), so there's no difference, but that's just ignoring the problem. At the very least, SmallRye Reactive Messaging creates all streams at application startup, which is very far from when the message handlers are called. If you use a hot publisher, you're typically also creating it far from the use site. I know SmallRye Health creates a `Uni` once and reuses it multiple times, again far from the creation site. (Far in time, not necessarily in space.) These usages might be a minority, but they are not insignificant, and they all cause troubles with context propagation.This is one thing I do not understand.Let's leave aside the current implementation of context propagation for a minute.To me the fact that a Uni is a computation almost makes the "context" problem easier. It no longer matters when the Uni was created, you just need to make sure that clients subscribe to a "wrapping" Uni that wraps the computation with some context setting/unsetting primitives. And those will automatically be executed on each subscription/execution.If the method is this:```@WithSomeContextUni<Void> doSomething() {...;
}```
To view this discussion visit https://groups.google.com/d/msgid/quarkus-dev/CAEqagpp8X9yw05z7D3LF7NJi5HcmMpUHWOyX95M7ESYMiV7hUA%40mail.gmail.com.
To view this discussion visit https://groups.google.com/d/msgid/quarkus-dev/CALbocOkORP4nGejergJyANXSybOt5fnZ%3DkY-fFDVmJYJ9nE29g%40mail.gmail.com.
pá 27. 3. 2026 v 15:54 odesílatel Stephane Epardaud <stephane...@gmail.com> napsal:
I unfortunately don't have a good name for the place I want the contexts to be captured. I can confidently say it must not be at `Uni`/`Multi` creation time, because that can happen far away from when its used. You can imagine the previous example to look like this:```javaUni<Void> result = Uni.createFrom().item(() -> doSomething(CDI.currentContext(), Transaction.current()));Uni<Void> baz() {return result;}```This is entirely valid and code like this exists out there (again, SmallRye Health). Contexts also must not be captured at subscription time, because at that time, they are gone. I think that contexts must be captured at `return result` and they must be "scoped" to the single subscription that's gonna happen later on (just like Mutiny's subscription-bound contexts.)
On Fri, Mar 27, 2026 at 12:09 PM Ladislav Thon <lad...@gmail.com> wrote:pá 27. 3. 2026 v 15:54 odesílatel Stephane Epardaud <stephane...@gmail.com> napsal:I unfortunately don't have a good name for the place I want the contexts to be captured. I can confidently say it must not be at `Uni`/`Multi` creation time, because that can happen far away from when its used. You can imagine the previous example to look like this:```javaUni<Void> result = Uni.createFrom().item(() -> doSomething(CDI.currentContext(), Transaction.current()));Uni<Void> baz() {return result;}```This is entirely valid and code like this exists out there (again, SmallRye Health). Contexts also must not be captured at subscription time, because at that time, they are gone. I think that contexts must be captured at `return result` and they must be "scoped" to the single subscription that's gonna happen later on (just like Mutiny's subscription-bound contexts.)Isn't at `return result` time exactly how @ActivateRequestContext [1] annotation works?
As Stef(?) said, the context will be gone by subscription time if I understand correctly how mutiny works.
I'm running into this at `return result` time problem with the new CDI scope types I'm defining/creating and I'm having to write an interceptor to make the scopes work.For example I'm creating an invocation scope which runs for the duration of the top-level method call. Only way to support mutiny return results is to weave in an interceptor to do this and to wrap the mutiny return result like the ActiveRequestContextInterceptor [1] does.
--
You received this message because you are subscribed to the Google Groups "Quarkus Development mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to quarkus-dev...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/quarkus-dev/CAL%3DE%3DjRjXVA6oFdxGuFwrq2g6XEy9_ca51xPXtyu1FtHo263nQ%40mail.gmail.com.