diff --git a/config/samples/clusters_v1beta1_cassandra.yaml b/config/samples/clusters_v1beta1_cassandra.yaml index a75269fcf..fb277ddd4 100644 --- a/config/samples/clusters_v1beta1_cassandra.yaml +++ b/config/samples/clusters_v1beta1_cassandra.yaml @@ -3,7 +3,7 @@ kind: Cassandra metadata: name: cassandra-cluster spec: - name: "username-Cassandra" + name: "bohdan-Cassandra" version: "4.0.10" privateNetworkCluster: false dataCentres: diff --git a/controllers/clusters/cassandra_controller.go b/controllers/clusters/cassandra_controller.go index 170da47e7..aaf959492 100644 --- a/controllers/clusters/cassandra_controller.go +++ b/controllers/clusters/cassandra_controller.go @@ -19,6 +19,7 @@ package clusters import ( "context" "errors" + "github.com/instaclustr/operator/pkg/reconcileutil" "strconv" "github.com/go-logr/logr" @@ -1307,5 +1308,5 @@ func (r *CassandraReconciler) SetupWithManager(mgr ctrl.Manager) error { event.Object.GetAnnotations()[models.ResourceStateAnnotation] = models.GenericEvent return true }, - })).Complete(r) + })).Complete(reconcileutil.ReconcilerWithLimit(r)) } diff --git a/main.go b/main.go index ac0ecfd6c..c12258543 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ limitations under the License. package main import ( + "context" "flag" "os" "time" @@ -89,6 +90,9 @@ func main() { HealthProbeBindAddress: probeAddr, LeaderElection: enableLeaderElection, LeaderElectionID: "680bba91.instaclustr.com", + BaseContext: func() context.Context { + return context.WithValue(context.Background(), "reconcile", "true") + }, // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily // when the Manager ends. This requires the binary to immediately end when the // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly diff --git a/pkg/reconcileutil/reconcile-limitation.go b/pkg/reconcileutil/reconcile-limitation.go new file mode 100644 index 000000000..301eda9bb --- /dev/null +++ b/pkg/reconcileutil/reconcile-limitation.go @@ -0,0 +1,61 @@ +package reconcileutil + +import ( + "context" + "fmt" + "github.com/instaclustr/operator/pkg/models" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" +) + +const maxReconcileRequeueRetries = 1 + +func ReconcilerWithLimit(r reconcile.Reconciler) reconcile.Func { + limiter := &ReconcileRequeueLimiter{ + maxRetries: maxReconcileRequeueRetries, + m: make(map[types.NamespacedName]int), + } + + return func(ctx context.Context, req reconcile.Request) (reconcile.Result, error) { + fmt.Println("Reconciler with limit") + if !limiter.RequeueAllowed(req.NamespacedName) { + fmt.Println("reconcile is not allowed") + l := log.FromContext(ctx) + l.Info("Amount of reconcile requeue retries reached its maximum for the resource", + "req", req.NamespacedName, + ) + + limiter.Reset(req.NamespacedName) + + return models.ExitReconcile, nil + } + + result, err := r.Reconcile(ctx, req) + if err != nil || result == models.ReconcileRequeue { + limiter.Requeue(req.NamespacedName) + return result, err + } + + limiter.Reset(req.NamespacedName) + + return result, nil + } +} + +type ReconcileRequeueLimiter struct { + maxRetries int + m map[types.NamespacedName]int +} + +func (r *ReconcileRequeueLimiter) Requeue(key types.NamespacedName) { + r.m[key]++ +} + +func (r *ReconcileRequeueLimiter) RequeueAllowed(key types.NamespacedName) bool { + return r.m[key] <= r.maxRetries +} + +func (r *ReconcileRequeueLimiter) Reset(key types.NamespacedName) { + delete(r.m, key) +}