Skip to content

Commit 465317a

Browse files
committed
Add AsyncOperationInProgress to ExternalObservation
When AsyncOperationInProgress is true, the managed reconciler sets Synced=False with reason ReconcilePending instead of ReconcileSuccess. This prevents a false Synced=True signal during long-running async operations (e.g. MSK cluster instance type changes). Fixes #941 Signed-off-by: Aj Nye <aj.nye@appian.com>
1 parent 3c37a9a commit 465317a

3 files changed

Lines changed: 36 additions & 2 deletions

File tree

apis/common/condition.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ const (
6363
ReasonReconcileSuccess ConditionReason = "ReconcileSuccess"
6464
ReasonReconcileError ConditionReason = "ReconcileError"
6565
ReasonReconcilePaused ConditionReason = "ReconcilePaused"
66+
ReasonReconcilePending ConditionReason = "ReconcilePending"
6667
)
6768

6869
// See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
@@ -312,3 +313,16 @@ func ReconcilePaused() Condition {
312313
Reason: ReasonReconcilePaused,
313314
}
314315
}
316+
317+
// ReconcilePending returns a condition indicating that reconciliation is
318+
// deferred pending an in-flight async operation. Unlike ReconcileError, this
319+
// does not trigger exponential backoff.
320+
func ReconcilePending(msg string) Condition {
321+
return Condition{
322+
Type: TypeSynced,
323+
Status: corev1.ConditionFalse,
324+
LastTransitionTime: metav1.Now(),
325+
Reason: ReasonReconcilePending,
326+
Message: msg,
327+
}
328+
}

apis/common/v1/condition.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const (
6060
ReasonReconcileSuccess = common.ReasonReconcileSuccess
6161
ReasonReconcileError = common.ReasonReconcileError
6262
ReasonReconcilePaused = common.ReasonReconcilePaused
63+
ReasonReconcilePending = common.ReasonReconcilePending
6364
)
6465

6566
// See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
@@ -134,3 +135,9 @@ func ReconcileError(err error) Condition {
134135
func ReconcilePaused() Condition {
135136
return common.ReconcilePaused()
136137
}
138+
139+
// ReconcilePending returns a condition indicating that reconciliation is
140+
// deferred pending an in-flight async operation.
141+
func ReconcilePending(msg string) Condition {
142+
return common.ReconcilePending(msg)
143+
}

pkg/reconciler/managed/reconciler.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,13 @@ type ExternalObservation struct {
526526
// finding where the observed diverges from the desired state.
527527
// The string should be a cmp.Diff that details the difference.
528528
Diff string
529+
530+
// AsyncOperationInProgress indicates that an asynchronous operation
531+
// (e.g. a long-running cloud API call) is currently in progress for
532+
// this resource. When true, the managed reconciler will set
533+
// Synced=False with reason ReconcilePending instead of
534+
// ReconcileSuccess, and will not call Update().
535+
AsyncOperationInProgress bool
529536
}
530537

531538
// An ExternalCreation is the result of the creation of an external resource.
@@ -1436,8 +1443,14 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (resu
14361443
// https://github.com/crossplane/crossplane/issues/289
14371444
reconcileAfter := r.pollIntervalHook(managed, r.pollInterval)
14381445
log.Debug("External resource is up to date", "requeue-after", time.Now().Add(reconcileAfter))
1439-
status.MarkConditions(xpv1.ReconcileSuccess())
1440-
r.metricRecorder.recordFirstTimeReady(managed)
1446+
1447+
if observation.AsyncOperationInProgress {
1448+
log.Debug("Async operation in progress, setting ReconcilePending")
1449+
status.MarkConditions(xpv1.ReconcilePending("Async operation in progress"))
1450+
} else {
1451+
status.MarkConditions(xpv1.ReconcileSuccess())
1452+
r.metricRecorder.recordFirstTimeReady(managed)
1453+
}
14411454

14421455
// record that we intentionally did not update the managed resource
14431456
// because no drift was detected. We call this so late in the reconcile

0 commit comments

Comments
 (0)