-
Notifications
You must be signed in to change notification settings - Fork 294
Support scale to zero rabbitMQ #1899
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
base: main
Are you sure you want to change the base?
Support scale to zero rabbitMQ #1899
Conversation
Thanks for the PR. Just FYI, I will certainly test this soon, but need to finish some other things first |
Some initial feedback:
I think it should be set to False when scaled to 0.
(it is not expected to work as we discussed, but the stacktrace shouldn't be there, unless there's a good reason for it)
|
Hello @mkuratczyk,
Thank you for the feedback |
|
Hello @mkuratczyk ! I did some change. 1- Now the ALLREPLICASREADY is false when is scaled to Kind regards |
Thanks. My only additional feedback is that the error message is a bit cryptic ("Cluster Scale from zero to other replicas than before configured not supported; tried to scale cluster from 3 nodes to 5 nodes"). Perhaps "unsupported operation: when scaling from zero, you can only restore the previous number of replicas (3)"? @Zerpet @ansd @MirahImage any thoughts about this PR? |
Hello, i changed the logger. |
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.
Thank you for contributing this PR! I left some comments with feedback that I would like to be addressed before merging.
func (r *RabbitmqClusterReconciler) scaleToZero(current, sts *appsv1.StatefulSet) bool { | ||
currentReplicas := *current.Spec.Replicas | ||
desiredReplicas := *sts.Spec.Replicas | ||
return desiredReplicas == 0 && currentReplicas > 0 | ||
} |
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.
This function does not need to be part of the RabbitmqClusterReconciler
, because it doesn't make any use of the struct functions or fields, it takes all its information from the arguments.
func (r *RabbitmqClusterReconciler) scaleFromZero(current, sts *appsv1.StatefulSet) bool { | ||
currentReplicas := *current.Spec.Replicas | ||
desiredReplicas := *sts.Spec.Replicas | ||
return currentReplicas == 0 && desiredReplicas > 0 | ||
} |
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.
This function does not need to be part of the RabbitmqClusterReconciler
, because it doesn't make any use of the struct functions or fields, it takes all its information from the arguments.
if err != nil { | ||
return true | ||
} |
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.
We should add a debug log line here indicating there was an error emitting the event and/or setting the status condition. At it is right now, it's silently ignoring the error.
In fact, since the function returns true
at this point in either case, you could simply log a debug message (without returning inside the if
) and return true after the if
conditional
@@ -213,7 +227,6 @@ func (r *RabbitmqClusterReconciler) Reconcile(ctx context.Context, req ctrl.Requ | |||
return ctrl.Result{}, err | |||
} | |||
} | |||
|
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 don't think this line break removal improves readability of this function. In fact, I think the opposite. This empty line makes the function cluttered. This line break separates high level steps of the reconcile process. Prior to this line break, it's the logic to reconcile the STS (plus other things earlier on), post this line break is the logic to update the STS and emit the relevant metadata. I believe this separation makes sense, and I want to keep unless there's a compelling argument for the opposite.
|
||
// Set ReconcileSuccess to true and update observedGeneration after all reconciliation steps have finished with no error | ||
rabbitmqCluster.Status.ObservedGeneration = rabbitmqCluster.GetGeneration() | ||
|
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.
Same as before with both the empty line removal and the new line addition.
if err != nil { | ||
return true | ||
} | ||
return true |
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.
Similar to my other comment:
We should add a debug log line here indicating there was an error emitting the event and/or setting the status condition. At it is right now, it's silently ignoring the error.
Since the function returns true at this point in either case, you could simply log a debug message (without returning inside the if err
) and return true after the if
conditional
var err error | ||
currentReplicas := *current.Spec.Replicas | ||
logger := ctrl.LoggerFrom(ctx) | ||
msg := "Cluster Scale down to 0 replicas." |
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.
msg := "Cluster Scale down to 0 replicas." | |
msg := "Cluster Scale down to 0 replicas" |
Log and/or event messages should not end with a dot .
err = r.updateAnnotation(ctx, cluster, cluster.Namespace, cluster.Name, beforeZeroReplicasConfigured, fmt.Sprint(currentReplicas)) | ||
r.Recorder.Event(cluster, corev1.EventTypeNormal, reason, msg) | ||
return err |
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.
err = r.updateAnnotation(ctx, cluster, cluster.Namespace, cluster.Name, beforeZeroReplicasConfigured, fmt.Sprint(currentReplicas)) | |
r.Recorder.Event(cluster, corev1.EventTypeNormal, reason, msg) | |
return err | |
r.Recorder.Event(cluster, corev1.EventTypeNormal, reason, msg) | |
return r.updateAnnotation(ctx, cluster, cluster.Namespace, cluster.Name, beforeZeroReplicasConfigured, fmt.Sprint(currentReplicas)) |
Event()
function does not use err
. We can simply return the function call.
logger := ctrl.LoggerFrom(ctx) | ||
var statusErr error | ||
logger.Error(errors.New(reason), msg) |
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 am confused. Why do we log an error unconditionally here?
This closes #1876
As talked with @Zerpet and @mkuratczyk in the issue we add some logic to allow scale to zero the rabbitMQ.
Also we add some logic to prevent the scale down when opt-out from zero.
We add new annotation
rabbitmq.com/before-zero-replicas-configured
to save the replicas configured before put rabbitMQ to zero.With this annotation we verify if the desired replicas after zero state are equals or greater than replicas before zero state.
If the replicas don't pass the verification it will works like
scaleDown
.Note to reviewers: remember to look at the commits in this PR and consider if they can be squashed
Summary Of Changes
Additional Context
Local Testing
Please ensure you run the unit, integration and system tests before approving the PR.
To run the unit and integration tests:
You will need to target a k8s cluster and have the operator deployed for running the system tests.
For example, for a Kubernetes context named
dev-bunny
: