-
-
Notifications
You must be signed in to change notification settings - Fork 314
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Runtime: Add WatchStreamExt::subscribe
#1131
Conversation
2dbc3a4
to
f8fb753
Compare
Sadly, I'm not sure this is a good fit for us, for a couple of reasons:
As for the clone issue, I think I'd generally rather |
@nightkr see #1128 (comment) for some context on this PR |
To address the other comments more specifically:
|
I'm sorry for the tone in my original reply. I don't want to shut this down, it's just a complicated topic that I'm scared of getting wrong. I'll go over the other PR to try to understand the use case better.
Yeah, that's a concern. In theory most consumers "should" be happy to take anything that can be derefed into the correct types, but that's kind of a pain to model properly in the type system.
I'd generally expect (when dealing with async stuff) that a sync function operates on the current state, while an async function (or stream) would try to make progress. Implicitly waiting for another external thing to make said progress exposes the user to deadlocks which are a pain to debug. We might be able to get around that by having the poller try to "steal" the backing stream, but I suspect that would cause a lot of thrashing.
I think that would still cause the same issue, you still have a "leader" stream and a "follower" stream, and you need to decide what happens when one consumer is making progress faster than the other. The other way to handle this would be to pause the faster consumers to let the slower ones catch up. But this also means that we're back to worrying about even more deadlocks. Maybe I'm overblowing the deadlock issue itself, and it'd be more pressing to make sure we have proper diagnostics for it when we suspect it. I don't know. |
Hm, as far as I can tell, |
If you go back to the first commits on the PR I had an implementation which allowed a controller to run from the same stream of events as a store. I encountered the problem that the The current It's entirely possible I'm going down the wrong path here and the correct solution is to stop the |
I think if it were an async function that would just deadlock I'd agree, but for a stream it feels entirely reasonable for it to just poll pending if there are no events on it yet. If Kubernetes has supplied no events then the |
Rust streams are pulled, not pushed, just like futures.
Ideally I think we'd share the same store too. I believe Go's controller library basically creates a new local stream by watching the store, something like that might be viable for us too. |
The initial implementation I was playing with did have the Controller sharing the same store too. Wouldn't a new stream created by watching the store have exactly the same problem you're worried about with this PR? If you didn't consume the original watch stream then the stream watching the store would also never progress. Apologies if I'm completely missing some nuance in the details here 😅. |
You're right. I don't know, for these cases that will probably just end up being a fact of life that we'll have to live with (and warn about in the documentation). Reasonable memory usage, guaranteed progress, reliable delivery... pick any two. :/ |
Codecov Report
📣 This organization is not using Codecov’s GitHub App Integration. We recommend you install it so Codecov can continue to function properly for your repositories. Learn more Additional details and impacted files@@ Coverage Diff @@
## main #1131 +/- ##
==========================================
- Coverage 72.79% 72.49% -0.31%
==========================================
Files 66 67 +1
Lines 5066 5087 +21
==========================================
Hits 3688 3688
- Misses 1378 1399 +21
|
I've added in an update where the
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks great with the Arc, but want to document and test the edge cases here.
That is possible.. but probably a pretty extensive change. I would want to see how much this affects the examples and general codebase before commit to an answer here. It is also possible that we make a new watcher like thing does this to let users move over in a non-breaking way somehow (we also have another generic extension in the works for watcher to allow doing watches on PartialObjectMeta types so there's more than one need) - but that does also limit the immediate controller usage (but we kind of also need some redesigning here to handle input streams so i think that is potentially OK). |
I guess an alternative would be to push the change down to the |
eb24e11
to
d4f30b1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests are good now 👍
minor nits on comments, will leave another comment on integration after.
As it stands we are creating the distinction between two types of streams:
Currently, this distinction makes it hard for us to use (even within controller i think):
as a longer term solution; I'm wondering if this should be Arc'd at the start and we should start sketching out a more comprehensive/configurable
I'll write up some thoughts about that in a separate issue. In either case, I think as it stands this PR is OK without further integration for now provided it's feature flagged while we sketch these things out; maybe under feat= |
70c6ccb
to
3610807
Compare
…event subscribers Signed-off-by: Dan Spencer <[email protected]>
1. Remove expensive cloning of Kubernetes objects 2. Allow propogation of err events Signed-off-by: Dan Spencer <[email protected]>
Co-authored-by: Eirik A <[email protected]> Signed-off-by: Dan Spencer <[email protected]>
Signed-off-by: Dan Spencer <[email protected]>
Signed-off-by: Dan Spencer <[email protected]>
Signed-off-by: Dan Spencer <[email protected]>
Signed-off-by: Dan Spencer <[email protected]>
Also renamed WatchStreamExt::subscribe to WatchStreamExt::stream_subscribe. The compiler was unable to tell if we were trying to call WatchStreamExt::subscribe or StreamSubscribe::subscribe when they were named the same. e.g. this code would not compile: let stream_subscribe = stream.subscribe(); let subscription = stream_subscribe.subscribe(); Signed-off-by: Dan Spencer <[email protected]>
3610807
to
539cbcd
Compare
WatchStreamExt::subscribe
Signed-off-by: Dan Spencer <[email protected]>
539cbcd
to
8b28a9b
Compare
Co-authored-by: Eirik A <[email protected]> Signed-off-by: Dan Spencer <[email protected]>
a7834c5
to
b2579da
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work, thank you so much. This is all good to me, apart from the DCO check that needs a --signoff
, but beyond that I am all happy to merge.
This PR has also helped me clarify some thoughts on how we can do unstable features (yes, people can accidentally enable these, but our most advanced use generally makes the most sense as a direct dependency so people generally have to opt-in to this).
Signed-off-by: Dan Spencer <[email protected]>
… feature Signed-off-by: Dan Spencer <[email protected]>
b2579da
to
e152543
Compare
…hed on by consumers Signed-off-by: Dan Spencer <[email protected]>
Was looking to merge this yesterday @danrspencer , but when updating with main and got the doctests to run properly, it has surfaced a minor problem with them. Are you able to have a look? |
Signed-off-by: Dan Spencer <[email protected]>
9ccde0c
to
7f91a6f
Compare
* Added stream_subscribe which allows watch streams to have additional event subscribers Signed-off-by: Dan Spencer <[email protected]> * StreamSubscribe now wraps items in arcs so that: 1. Remove expensive cloning of Kubernetes objects 2. Allow propogation of err events Signed-off-by: Dan Spencer <[email protected]> * Renamed watch_ext subscribable to subscribe Co-authored-by: Eirik A <[email protected]> Signed-off-by: Dan Spencer <[email protected]> * StreamSubscribe now allows subscribers how to handle lagging Signed-off-by: Dan Spencer <[email protected]> * Fixed clippy errors in StreamSubscribe Signed-off-by: Dan Spencer <[email protected]> * Fixed grammar in StreamSubscribe docs Signed-off-by: Dan Spencer <[email protected]> * Fixed rustfmt errors in StreamSubscribe Signed-off-by: Dan Spencer <[email protected]> * Improved the documentation for WatchStreamExt::stream_subscribe method. Also renamed WatchStreamExt::subscribe to WatchStreamExt::stream_subscribe. The compiler was unable to tell if we were trying to call WatchStreamExt::subscribe or StreamSubscribe::subscribe when they were named the same. e.g. this code would not compile: let stream_subscribe = stream.subscribe(); let subscription = stream_subscribe.subscribe(); Signed-off-by: Dan Spencer <[email protected]> * Put StreamSubscribe behind a feature flag unstable_runtime_subscribe Signed-off-by: Dan Spencer <[email protected]> * Update kube-runtime/src/utils/mod.rs Co-authored-by: Eirik A <[email protected]> Signed-off-by: Dan Spencer <[email protected]> * Fixed rustfmt error in kube-runtime utils mod.rs Signed-off-by: Dan Spencer <[email protected]> * Fixed incorrect feature flag usage for the unstable-runtime-subscribe feature Signed-off-by: Dan Spencer <[email protected]> * Made substream_subscribe pub so that its error can be accessed / matched on by consumers Signed-off-by: Dan Spencer <[email protected]> * Fixed issue with doctest for stream_subscribe Signed-off-by: Dan Spencer <[email protected]> --------- Signed-off-by: Dan Spencer <[email protected]> Co-authored-by: Eirik A <[email protected]>
Motivation
It may be desirable to have subscribe to the events from a watcher without taking ownership of the stream itself. For example this allows a controller to be created via the
applier
without consuming the original watcher stream.Solution
Added an extension method in
watch_ext
which produces astream_subscriber
. Success events (T
must implement clone, so we can't send errors to subscribers) are propagated to all subscribers as the original stream is consumed.