-
Notifications
You must be signed in to change notification settings - Fork 117
Refactor status collector architecture with structured errors #2016
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?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
[codespell] | ||
ignore-words-list = NotIn,notin,AfterAll,ND,aks | ||
ignore-words-list = NotIn,notin,AfterAll,ND,aks,deriver | ||
skip = *.svg,*.mod,*.sum |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ import ( | |
|
||
// StatusCollector collects status changes during reconciliation | ||
// and applies them in a single batch update at the end. | ||
// It implements the Collector interface. | ||
// It implements the StatusManager interface. | ||
type StatusCollector struct { | ||
mcpRegistry *mcpv1alpha1.MCPRegistry | ||
hasChanges bool | ||
|
@@ -24,14 +24,36 @@ type StatusCollector struct { | |
syncStatus *mcpv1alpha1.SyncStatus | ||
apiStatus *mcpv1alpha1.APIStatus | ||
conditions map[string]metav1.Condition | ||
|
||
// Component collectors | ||
syncCollector *syncStatusCollector | ||
apiCollector *apiStatusCollector | ||
} | ||
|
||
// syncStatusCollector implements SyncStatusCollector | ||
type syncStatusCollector struct { | ||
parent *StatusCollector | ||
} | ||
|
||
// apiStatusCollector implements APIStatusCollector | ||
type apiStatusCollector struct { | ||
parent *StatusCollector | ||
} | ||
|
||
// NewStatusManager creates a new StatusManager for the given MCPRegistry resource. | ||
func NewStatusManager(mcpRegistry *mcpv1alpha1.MCPRegistry) StatusManager { | ||
return newStatusCollector(mcpRegistry) | ||
} | ||
|
||
// NewCollector creates a new status update collector for the given MCPRegistry resource. | ||
func NewCollector(mcpRegistry *mcpv1alpha1.MCPRegistry) Collector { | ||
return &StatusCollector{ | ||
// newStatusCollector creates the internal StatusCollector implementation | ||
func newStatusCollector(mcpRegistry *mcpv1alpha1.MCPRegistry) *StatusCollector { | ||
collector := &StatusCollector{ | ||
mcpRegistry: mcpRegistry, | ||
conditions: make(map[string]metav1.Condition), | ||
} | ||
collector.syncCollector = &syncStatusCollector{parent: collector} | ||
collector.apiCollector = &apiStatusCollector{parent: collector} | ||
return collector | ||
} | ||
|
||
// SetPhase sets the phase to be updated. | ||
|
@@ -46,17 +68,22 @@ func (s *StatusCollector) SetMessage(message string) { | |
s.hasChanges = true | ||
} | ||
|
||
// SetAPIReadyCondition adds or updates the API ready condition. | ||
func (s *StatusCollector) SetAPIReadyCondition(reason, message string, status metav1.ConditionStatus) { | ||
s.conditions[mcpv1alpha1.ConditionAPIReady] = metav1.Condition{ | ||
Type: mcpv1alpha1.ConditionAPIReady, | ||
// SetCondition sets a general condition with the specified type, reason, message, and status | ||
func (s *StatusCollector) SetCondition(conditionType, reason, message string, status metav1.ConditionStatus) { | ||
s.conditions[conditionType] = metav1.Condition{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not strictly cause by your patch but since we have multiple methods writing into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIRC, controller-runtime ensures single-threaded execution per resource instance. Within a single reconciliation, all method calls are sequential, not concurrent. So, Im not sure we need any synchronized data access, given that each reconciliation creates a new StatusManager with its own map of conditions. |
||
Type: conditionType, | ||
Status: status, | ||
Reason: reason, | ||
Message: message, | ||
} | ||
s.hasChanges = true | ||
} | ||
|
||
// SetAPIReadyCondition adds or updates the API ready condition. | ||
func (s *StatusCollector) SetAPIReadyCondition(reason, message string, status metav1.ConditionStatus) { | ||
s.SetCondition(mcpv1alpha1.ConditionAPIReady, reason, message, status) | ||
} | ||
|
||
// SetSyncStatus sets the detailed sync status. | ||
func (s *StatusCollector) SetSyncStatus( | ||
phase mcpv1alpha1.SyncPhase, message string, attemptCount int, | ||
|
@@ -148,3 +175,47 @@ func (s *StatusCollector) Apply(ctx context.Context, k8sClient client.Client) er | |
|
||
return nil | ||
} | ||
|
||
// StatusManager interface methods | ||
|
||
// Sync returns the sync status collector | ||
func (s *StatusCollector) Sync() SyncStatusCollector { | ||
return s.syncCollector | ||
} | ||
|
||
// API returns the API status collector | ||
func (s *StatusCollector) API() APIStatusCollector { | ||
return s.apiCollector | ||
} | ||
|
||
// SetOverallStatus sets the overall phase and message explicitly (for special cases) | ||
func (s *StatusCollector) SetOverallStatus(phase mcpv1alpha1.MCPRegistryPhase, message string) { | ||
s.SetPhase(phase) | ||
s.SetMessage(message) | ||
} | ||
|
||
// SyncStatusCollector implementation | ||
|
||
// SetSyncCondition sets a sync-related condition | ||
func (sc *syncStatusCollector) SetSyncCondition(condition metav1.Condition) { | ||
sc.parent.conditions[condition.Type] = condition | ||
sc.parent.hasChanges = true | ||
} | ||
|
||
// SetSyncStatus delegates to the parent's SetSyncStatus method | ||
func (sc *syncStatusCollector) SetSyncStatus(phase mcpv1alpha1.SyncPhase, message string, attemptCount int, | ||
lastSyncTime *metav1.Time, lastSyncHash string, serverCount int) { | ||
sc.parent.SetSyncStatus(phase, message, attemptCount, lastSyncTime, lastSyncHash, serverCount) | ||
} | ||
|
||
// APIStatusCollector implementation | ||
|
||
// SetAPIStatus delegates to the parent's SetAPIStatus method | ||
func (ac *apiStatusCollector) SetAPIStatus(phase mcpv1alpha1.APIPhase, message string, endpoint string) { | ||
ac.parent.SetAPIStatus(phase, message, endpoint) | ||
} | ||
|
||
// SetAPIReadyCondition delegates to the parent's SetAPIReadyCondition method | ||
func (ac *apiStatusCollector) SetAPIReadyCondition(reason, message string, status metav1.ConditionStatus) { | ||
ac.parent.SetAPIReadyCondition(reason, message, status) | ||
} |
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.
why wasn't it covered here, is it complex to retrieve?