diff --git a/internal/controllers/core/liveupdate/reconciler.go b/internal/controllers/core/liveupdate/reconciler.go index d60ac5c651..794fb0f1fb 100644 --- a/internal/controllers/core/liveupdate/reconciler.go +++ b/internal/controllers/core/liveupdate/reconciler.go @@ -114,8 +114,13 @@ func NewFakeReconciler( } func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - r.mu.Lock() - defer r.mu.Unlock() + state := r.store.RLockState() + available := state.AvailableBuildSlots() + r.store.RUnlockState() + + if available < 1 { + return ctrl.Result{RequeueAfter: 100 * time.Millisecond}, nil + } lu := &v1alpha1.LiveUpdate{} err := r.client.Get(ctx, req.NamespacedName, lu) @@ -126,7 +131,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu if apierrors.IsNotFound(err) || lu.ObjectMeta.DeletionTimestamp != nil { r.store.Dispatch(liveupdates.NewLiveUpdateDeleteAction(req.Name)) - delete(r.monitors, req.Name) + r.deleteMonitor(req.Name) return ctrl.Result{}, nil } @@ -249,9 +254,21 @@ func (r *Reconciler) handleFailure(ctx context.Context, lu *v1alpha1.LiveUpdate, return ctrl.Result{}, err } +// Remove a monitor when its LiveUpdate is deleted. +// Locks because r.monitors may be accessed concurrently. +func (r *Reconciler) deleteMonitor(name string) { + r.mu.Lock() + defer r.mu.Unlock() + delete(r.monitors, name) +} + // Create the monitor that tracks a live update. If the live update // spec changes, wipe out all accumulated state. +// Locks because r.monitors may be accessed concurrently. func (r *Reconciler) ensureMonitorExists(name string, obj *v1alpha1.LiveUpdate) *monitor { + r.mu.Lock() + defer r.mu.Unlock() + spec := obj.Spec m, ok := r.monitors[name] if ok && apicmp.DeepEqual(obj.Spec, m.spec) {