fix(connection): honor always-update for ready resources#407
Conversation
|
@freeznet:Thanks for your contribution. For this PR, do we need to update docs? |
There was a problem hiding this comment.
Pull request overview
This PR updates the PulsarConnection reconciliation flow to honor the AlwaysUpdatePulsarResource feature gate so that managed child resources can be re-applied even when they are already Ready=True (useful for upgrade remediation), and documents/exposes that behavior via Helm values and docs.
Changes:
- Continue connection reconciliation for “ready-only” child sets when
AlwaysUpdatePulsarResourceis enabled and at least one managed child resource is observed. - Add unit tests covering always-update enabled/disabled behavior and ensuring the deletion guard behavior remains intact.
- Document reconciliation skip semantics and surface the feature toggle guidance in docs and Helm chart metadata.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pkg/connection/reconciler.go | Enables reconciling ready resources when always-update is on; adds helper methods to detect observed children. |
| pkg/connection/reconciler_test.go | Adds tests validating reconcile behavior with always-update on/off and during connection deletion. |
| docs/pulsar_resource_lifecycle.md | Documents the reconciliation skip contract and upgrade remediation options (incl. always-update). |
| docs/pulsar_namespace.md | Adds a note pointing to the lifecycle doc section for reconciliation skip behavior and remediation. |
| charts/pulsar-resources-operator/values.yaml | Improves Helm values documentation for features.alwaysUpdatePulsarResource. |
| charts/pulsar-resources-operator/README.md | Updates the chart values table description for features.alwaysUpdatePulsarResource. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
maxsxu
left a comment
There was a problem hiding this comment.
Reviewed the PR. The reconciler behavior looks sound to me: with AlwaysUpdatePulsarResource enabled it re-enters child reconciliation for observed ready resources, while the deleting-connection remaining-resource guard stays ahead of the always-update path. The focused tests cover the skip path, always-update path, no-op connection/status updates, and deletion guard.
One cleanup item before merge:
go.sumappears to contain unrelated extra module checksums. I rango mod tidy -diffon this branch and it wants to remove the added checksum-only churn, including the largecloud.google.com/go/*, Docker, etcd, and othergo.modentries. Since this PR does not changego.mod, please rungo mod tidyand commit the resultinggo.sumso the dependency metadata stays minimal.
Verification:
GOCACHE=/private/tmp/pro-go-build-cache GOMODCACHE=/private/tmp/pro-go-mod-cache go test ./pkg/connectionpassed.GOCACHE=/private/tmp/pro-go-build-cache GOMODCACHE=/private/tmp/pro-go-mod-cache go mod tidy -diffreported thego.sumcleanup above.
maxsxu
left a comment
There was a problem hiding this comment.
PR Review: fix(connection): honor always-update for ready resources
Summary
This PR makes the PulsarConnectionReconciler honor the AlwaysUpdatePulsarResource feature gate for child resources that are already Ready. Previously, once a resource was Ready, it was never reconciled again — even when AlwaysUpdatePulsarResource was enabled. This is important for upgrade remediation scenarios where a new operator version introduces a new spec field but existing resources remain Ready at the same generation.
The PR also adds several quality-of-life improvements:
- Avoids no-op Kubernetes API writes (both
.Update()and.Status().Update()) by comparing before/after state - Adds comprehensive unit tests covering the new behavior
- Improves documentation for the
alwaysUpdatePulsarResourcefeature and the reconciliation skip contract - Updates Helm chart descriptions
Positive Aspects
- Well-structured logic: The
shouldReconcileReadyResources()andhasObservedResource()helpers are clean and readable. - Good test coverage: Four test scenarios covering disabled, enabled, no-op avoidance, and deletion guard — exactly the right cases.
- Defensive status updates: The
updateConnectionStatusIfChangedpattern usingequality.Semantic.DeepEqualis a solid way to avoid unnecessary API calls and potential conflict retries. - No-op connection update avoidance: Checking
controllerutil.AddFinalizerreturn value and theconnectionChangedflag to skip redundantclient.Update()calls is a nice improvement. - Documentation: The new
pulsar_resource_lifecycle.mdsection clearly explains the reconciliation skip behavior and recovery options.
Suggestions
-
hasObservedResourcecompleteness: The method checks all 10 resource types, which matches the fields onPulsarConnectionReconciler. This looks complete but is fragile — if a new resource type is added to the struct, someone could forget to add it here. Consider adding a comment noting this coupling, or alternatively, keeping the reconcilers list length as a proxy (though that wouldn't account for empty slices). -
Deletion path with
AlwaysUpdatePulsarResourceenabled: When the connection is being deleted (DeletionTimestampis set) and there are no unready resources but there are remaining resources (tenants, namespaces, etc.), the current code correctly does NOT reconcile — it still just logs the remaining-resource guard. However, the deletion guard only checkstenants,namespaces,topics, andgeoReplications. Other resource types likepermissions,packages,sinks,sources,functions, andnsIsolationPoliciesare not checked. This is pre-existing behavior but worth noting as a potential gap. -
Test helper
setAlwaysUpdatePulsarResource: The helper calls itself recursively in the cleanup —setAlwaysUpdatePulsarResource→t.Cleanup(func() { setAlwaysUpdatePulsarResource(t, false) })— but the inner call is to the unwrappedsetAlwaysUpdatePulsarResource(withoutForTest), so this is correct but slightly confusing naming. Minor style nit. -
go.sumchurn: Thego.sumdiff adds 243 lines with zero deletions. This is a large expansion of indirect dependency checksums. It's likely caused by a Go toolchain or dependency update. Not a blocker, but it's worth confirming this is expected and not an accidentalgo mod tidywith a different Go version. -
PR description: The PR body is the default template with no actual content filled in (motivation, modifications, verification are all placeholders). It would be helpful to fill this in for future reference.
Verdict
The core logic is sound, the tests are well-designed, and the documentation additions are valuable. The no-op avoidance is a nice touch that reduces unnecessary API server load. LGTM overall — the suggestions above are minor and non-blocking.
* fix(connection): honor always-update for ready resources * fix(connection): avoid noop connection updates * chore: add PLAN.md to .gitignore * build(deps): update go.sum with new dependencies --------- Co-authored-by: Max Xu <xuhuan@live.cn>
(If this PR fixes a github issue, please add
Fixes #<xyz>.)Fixes #
(or if this PR is one task of a github issue, please add
Master Issue: #<xyz>to link to the master issue.)Master Issue: #
Motivation
Explain here the context, and why you're making that change. What is the problem you're trying to solve.
Modifications
Describe the modifications you've done.
Verifying this change
(Please pick either of the following options)
This change is a trivial rework / code cleanup without any test coverage.
(or)
This change is already covered by existing tests, such as (please describe tests).
(or)
This change added tests and can be verified as follows:
(example:)
Documentation
Check the box below.
Need to update docs?
doc-required(If you need help on updating docs, create a doc issue)
no-need-doc(Please explain why)
doc(If this PR contains doc changes)