Conversation
- Added a section on how to build the context - Added a section on how to attach a context - Simplified the Multi docs with Uni - Removed context attachment from docs about accessing the context - Reworked indentation so it fits - Removed "pipeline" names in favour of uni/multi
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2037 +/- ##
============================================
+ Coverage 89.18% 89.19% +0.01%
- Complexity 3120 3124 +4
============================================
Files 412 412
Lines 13295 13295
Branches 1688 1688
============================================
+ Hits 11857 11859 +2
+ Misses 812 808 -4
- Partials 626 628 +2 🚀 New features to boost your workflow:
|
so ... don't leave me hanging like this ... what are the semantics of context propagation when you fork the stream (and what are the semantics when you later join the branches). |
Very good question. This appears to be undefined, and not even mentioned. I suppose we could make guesses as to how each contextual data works with fork/joins:
In short, I think it depends on the context. But in the docs, it's not even mentioned and so most people won't be aware of the issue and its problems and solutions. |
|
Hey @FroMage sorry for taking a while to get back to this. Thanks for proposing documentation updates on Mutiny contexts / what's in the draft here is already a solid improvement. On terminology:
|
|
A note of how this API was designed, and thinking out loud You'll find similar constructs in Reactor (see https://projectreactor.io/docs/core/release/reference/advancedFeatures/context.html), but the Mutiny interpretation of what a context API should be differs (basically Reactor has immutability and a mutation operator, etc). My idea was that each operator in a pipeline should have some context to avoid lambda captures of relevant input information (e.g., you get an item, and you want to use Such reactive APIs are subscription-based:
It hence made sense to tie contexts to subscriptions, because this is what defines when some asynchronous processing starts. This is why the context data gets passed to the subscription. Operators get passed the context from their subscribers, so effectively all operators in a pipeline share the same subscription-bound context. This is very fine in a model where contexts are essentially meant to convey input data that's relevant for the whole pipeline logic (e.g., correlation identifiers) while the output results leverage the reactive flow ( In short: it was more designed to be read than to be written. Now if writing becomes important there are indeed a few shortcomings in all operators sharing the same context reference.
|
Let me try to sum up what I think we can do to improve from the context docs:
Terminology
The terminology is confusing to me. This is more about the API names, because the names chosen
attachContextandwithContextare either ambiguous or do the opposite of what people expect.Normally,
attachingis the operation of taking something from outside and tacking it on to something. In this scenario, it should mean taking a context and binding it to a pipeline. So, attaching it to the pipeline.It does not, in most people's mind, imply that this is how you access a previously attached/bound context from a pipeline.
So,
attachContextshould be renamed something likeaccessContextorreifyContext(although nobody knows that correct term), or evenmaterializeContext(as you use that term sometimes, which is probably correct, but just like reify I suppose most people won't understand that it means, for all intends and purposes here: access a context). It could begetContext,readContext,accessContext,obtainContext…Now,
withContextis also problematic because it's ambiguous: there's one interpretation of it that does exactly what it currently does, which is "pair/bundle/wrap the item with the context". But there's also a much more commonly used interpretation where it means exactly the opposite: "attach a context to this pipeline / run this pipeline with this context".In fact, I was convinced this was how to attach a context. Case in point,
subscribe().withuses the same verb.So the
withContextoperation also allows people to access the context. The difference withattachContextis that one is called during subscription and the other during item production.I am not sure how it should be named, but I am 100% sure that the current names are confusing. I guess we should discuss this to see if a better name emerges.
What contexts do and are used for
I think there's a blob of text missing that explains that the contexts flow from subscription to the entire Uni pipeline and that this is useful to propagate contexts from one end of the pipeline to another.
There's probably a section missing about how people should use this, as evidenced by our Zulip discussion, about either modifying the context, or creating subcontexs, and how these contexts work with
Uni.combine.I suppose the question ultimately is about branches (
Uni.combine) but also scopes: how do you deal with contexts that span from one part of the pipeline until another part?I suppose one example would help. I bet this is a common use-case.
Missing operation?
I think we should add an API for switching the context as part of the pipeline, like the one I documented:
I suppose this could be
Uni<T> Uni.switchContext(Context)oroverrideContextorwithContextdepending on what we do with the "access context on subscription" operation that is currently using that name.This might depend on the discussion above about scopes of contexts and how to modify or override them.
What this PR already contains
transformToUniAndMergeoperations were adding complexity that I felt were not relevant to the docs. Unis are just simpler to use as examples.unimakes it simpler and obvious what we're talking about.This PR is not complete, I figured it's a good start and we can start discussing it next year and I can continue working on it after we hit some consensus :)