-
-
Notifications
You must be signed in to change notification settings - Fork 329
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
ReconcilerAction should be an enum #317
Comments
From the reconciler's PoV all of those cases are already supported. ( Do you have a specific use-case in mind that would require this? |
I didn't say that anything isn't support. I just looks awkward to me from a Rust perspective. Take the
I think the The same for the actual implementation returning a result: fn reconcile() -> Result<ReconcilerAction> {
Ok(ReconcileResult{requeue_after: None})
}
// or
fn reconcile() -> Result<ReconcilerAction> {
Ok(ReconcileResult::default())
} That looks simple awkward to me, versus: fn reconcile() -> Result<ReconcilerAction> {
Ok(Done)
} So again, it is not about "making it work", it is about making a nice API that aligns with Rust concepts. |
Yeah.. but as a user you should rarely be matching on the
Disabling periodic reconciliation should (IMO) feel somewhat awkward, since it's rarely something that you want to do. External systems change, and it's easy to forget to watch some subresource. Periodic reconciliation helps mitigate both of those cases (but is of course strictly worse than a proper watch). There are only a few cases where you are truly done with a resource, and legitimately don't care anymore (for example: a |
I could agree that it would be slightly more clear to have something like:
But that seems like a very marginal gain to me. I'm not so sure about making |
I got interested in this issue :) Well, I created a small showcase pullrequest to better imagine how the change would look like. #338 I don't have all the @teozkr has,but with my limited knowledge from user's perspective, the enum is also what I would expect and the struct was a little bit unexpected. Secondly, you mention there will be a lot more actions in the future, mutually exclusive with re-scheduling the reconciliation after some delay. That seems fine to me, as there will one be one enum level with rescheduling. The pub enum ReconcilerAction {
Requeue(Duration),
None,
ActionX,
ActionY,
ActionZ,
SomeOtherDelayedTaskThatOccured(Duration),
///etc
} Also, the original proposal had Just my two cents. |
I said they will likely not be mutually exclusive with rescheduling. Apart from that, I don't want to promote "never requeue" as the common or easy option.. the existing |
Thanks a lot @Pscheidl . I agree with the enum being the more expected solution compared to master, and your PR illustrates that. This does intersect with another case that was in development; if we wanted to add a case like I feel that either we expose So the question I think is really, what are our use cases for other ReconcilerActions? Some thoughts:
Which of these are the most useful? |
The PR of mine can be discarded, it was meant just to try it out (talk is cheap, I wanted the code). My apologies to @teozkr for misreading the info above. How will the exponential backoff work ? Ideally, as far as I understand, the controller should be failure-tolerant. E.g. finalizers stay in the resource metadata unless explicitely removed by the controller, making sure if the controller is down, nothing happens. There seems to be a hashmap in this PR: https://github.com/clux/kube-rs/pull/314/files#diff-e8024b5d2267b4aa47ca3f4fcc5d2338edbee63a282057b55fe3b13ebc28cabaR137 If the controller fails, the time of last reconciliation is lost. That's acceptable probably. Not sure. Just thinking out loud. Another thought is the RequeueAfter - if we were somehow able to persist the times in the Kubernetes object itself, it would be easy provide users with the option to specify their own function, which would provide time of next reconciliation. This seems like a generic way to solve many problems - instead of having two levels of that enum just for requeing after certain amount of time, there could be one accepting a Anyway, I do think exponential backoff is useful, as working deployments need to be checked periodically, often they can fail (in ours cases, users might cause them to fail) and resources have to be cleaned in case of failure. Such a period can be prolonged after a while, not to stress Kubernetes that much. At least that's how I think about it - I always try for the code to be nice to its surroundings. |
Revisiting this after writing docs. It's clear that this interface is still one of the awkward ones, and it's front and centre, so would like to address this. In the lifespan of this issue we have NOT had any other reasonable requests for other modes of reconcile actions to be taken. Controller-runtime has exactly mode (requeAfter) to configure - albeit with an awkward bool to set it. The only potential option that makes sense to me would be a backoff based one, but I think we already support this by adding a Ultimately, the two options we have here are either:
So I propose that rather than have the escape hook be a magic I.e.: pub enum Action {
/// When to next trigger the reconciliation if no external watch triggers hit
///
/// This is the best-practice action that ensures eventual consistency of your controller
/// even in the case of missed changes (which can happen).
///
/// Watch events are not normally missed, so running this once per hour as a fallback is reasonable.
Requeue(Duration),
/// Do nothing until a change is detected
///
/// This stops the controller periodically reconciling this object until a relevant watch event
/// was **detected**.
///
/// **Warning**: If you have watch desyncs, it is possible to miss changes entirely.
/// It is therefore not recommended to disable requeuing this way, unless you have
/// frequent changes to the underlying object, or some other hook to retain eventual consistency.
AwaitChange,
} as a benefit we get the much snappier reconcile impls: - Ok(ReconcilerAction {
- requeue_after: Some(Duration::from_secs(300)),
- })
+ Ok(Action::Requeue(Duration::from_secs(300))) |
How about adding associated functions, so it'd be |
Sure, that makes sense to me. Also makes the change in applier easier. |
fixes #317 Signed-off-by: clux <[email protected]>
* Change ReconcileAction to Action and add associated ctors fixes #317 Signed-off-by: clux <[email protected]> * clippy Signed-off-by: clux <[email protected]> * clippy + docs Signed-off-by: clux <[email protected]> * fix extraneous doc warnings in entry Signed-off-by: clux <[email protected]> * remove Default for Action Signed-off-by: clux <[email protected]> * fix secret-syncer Signed-off-by: clux <[email protected]> * fix remaining references to reconciler action Signed-off-by: clux <[email protected]>
IMHO
ReconcilerAction
should be an enum, rather than a struct. This would handling the outcome much simpler.I would imagine something like:
Or maybe:
This would allow you to handle outcomes like this:
The text was updated successfully, but these errors were encountered: