Skip to content
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

reflector api redesign #102

Closed
clux opened this issue Dec 18, 2019 · 3 comments · Fixed by #258
Closed

reflector api redesign #102

clux opened this issue Dec 18, 2019 · 3 comments · Fixed by #258
Labels
question Direction unclear; possibly a bug, possibly could be improved. runtime controller runtime related

Comments

@clux
Copy link
Member

clux commented Dec 18, 2019

Reflector as it stands in async land is awkward and not very user friendly. A few reasons for this:

Polling does not need to be done by the consumer

You must drive a Reflector with .poll() inside the app, but the app doesn't get anything back from this, as it only serves to drive internal state management. This is in contrast to the Informer whose poll() returns the literal Stream of WatchEvents (making it a lot more useful).

This means most Reflector get this leads to this type of logic: https://github.com/clux/version-rs/blob/f636f8d66eb2e2f2019b8b0a0467a77b2fd133a2/version.rs#L50-L62

It might be better to just hide the polling action inside the Reflector, even if this forces us to expose an error handling callback FnOnce or an ErrorHandlingPolicy enum with ExponentialBackoff (we do backoff) + SelfTerminate (k8s does backoff).

Hidden information / state getters insufficient

With the events hidden from the app, it's hard to keep any secondary states up to date. If you want to keep a different data structure as your cache you need to apply a transform yourself periodically. It might be better to expose the events, or the keys of the changed resources.

This leads to this type of logic: https://github.com/clux/version-rs/blob/f636f8d66eb2e2f2019b8b0a0467a77b2fd133a2/version.rs#L70-L79

Here we've badly tied the internal update to the watch timeout (300s by default now) because they already have to do one pointless timer. If they have to do a timer, they should really only have to do the ones that matter to them. But it's also possible we should expose a Reflector::transform function to pass through Modified events through so the cache inside the Reflector is always kept correct with the information the app always care about.

notes

These changes would mean that Reflector and Informer APIs deviate a bit more from each other, but they should serve different, and real purposes here. We're not tied to the golang api for the abstractions, they're just inspirations at this point.

@clux clux added enhancement question Direction unclear; possibly a bug, possibly could be improved. labels Dec 18, 2019
@xguerin
Copy link

xguerin commented Jan 7, 2020

A pattern I find very useful in my applications is to both allow the application to react on incoming Kubernetes events while still maintaining the cache of Kubernetes objects. This combination is nicely laid out in this blog post and I believe is also available in the Go client, although since I never used it I cannot say for sure.

In essence, it would be the Informer/Reflector pattern merged into one. I gave it a shot here https://github.com/xguerin/kube-rs/tree/feature/controller. It's probably not the best implementation but it achieves the goal stated above.

@clux
Copy link
Member Author

clux commented Feb 12, 2020

Late response, but appreciate your change here @xguerin ! I think we do need to expose some kind of combination for sure.

Will be trying to look at this this week and will investigate more whether to take more inspiration from the controller-runtime package that seems to have spun out of kubebuilder. The go ecosystem have matured quite a bit and there are nicer abstractions to take inspiration from that we can package up in some - hopefully a nicer - way in rust.

Might create a Controller type that just tells you when to reconcile as well.

@clux clux added the runtime controller runtime related label Feb 26, 2020
@clux clux added this to the kubecon-eu-2020 milestone Feb 26, 2020
@clux clux removed the enhancement label Feb 27, 2020
clux added a commit that referenced this issue Apr 8, 2020
in an effort to solve #102 we try to factor out the implicit data store
inside Reflector<K> as a trait object that can be customized.

The abstraction, feels very rigid, and not sure how useable it is.
Ultimately, I wanted a nicer interface for users of library that wasnt
"give me a CLONE of ALL state" or "give me one thing with a matching
ID".

It's potentially possible to take type that implemented iterator with
this approach, as well as MAYBE handing out an arc'd clone to users
(provided they are told not to keep it locked for ages).

Another problem I wanted to solve was having the stored state be a
simplified version of the underlying data (i.e. add/modify would perform
some kind of transformation before storing it). This was super awkward
with the old Reflector setup because you'd effectively force two whole
clones of the two types, and you'd have to recreate your shadow tree
every time you asked for the state (which was ALL of the input).
@clux clux linked a pull request Jul 17, 2020 that will close this issue
6 tasks
@clux
Copy link
Member Author

clux commented Jul 17, 2020

The new reflector from Theo's runtime (in #258) will address these concerns and is a complete rewrite.

@clux clux closed this as completed in #258 Jul 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Direction unclear; possibly a bug, possibly could be improved. runtime controller runtime related
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants