Skip to content

Commit 37a1e48

Browse files
committed
feat: implement StatusPatch for batched status updates in session handling
- Introduced a new StatusPatch type to accumulate status field updates and condition changes, allowing for a single API call to apply multiple changes. - Updated session event handling to utilize StatusPatch, improving efficiency by reducing the number of API calls during status updates. - Enhanced the handling of session phases, including 'Pending', 'Stopped', and 'Creating', to ensure accurate state management and reduce race conditions. - Improved logging for better visibility into session state transitions and updates. These changes enhance the robustness and performance of session management by streamlining status updates and reducing the frequency of API calls.
1 parent bd8a3e4 commit 37a1e48

File tree

2 files changed

+736
-291
lines changed

2 files changed

+736
-291
lines changed

components/operator/internal/handlers/helpers.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,86 @@ type conditionUpdate struct {
4646
Message string
4747
}
4848

49+
// StatusPatch accumulates status field updates and condition changes
50+
// before applying them in a single batch update. This reduces watch events
51+
// by batching multiple status changes into one API call.
52+
type StatusPatch struct {
53+
Fields map[string]interface{}
54+
Conditions []conditionUpdate
55+
Deletions map[string]bool // Fields to delete
56+
Namespace string
57+
Name string
58+
}
59+
60+
// NewStatusPatch creates a new status accumulator for the given session.
61+
func NewStatusPatch(namespace, name string) *StatusPatch {
62+
return &StatusPatch{
63+
Fields: make(map[string]interface{}),
64+
Conditions: make([]conditionUpdate, 0),
65+
Deletions: make(map[string]bool),
66+
Namespace: namespace,
67+
Name: name,
68+
}
69+
}
70+
71+
// SetField queues a field update to be applied when Apply() is called.
72+
func (sp *StatusPatch) SetField(key string, value interface{}) {
73+
delete(sp.Deletions, key) // Remove from deletions if it was there
74+
sp.Fields[key] = value
75+
}
76+
77+
// DeleteField queues a field deletion to be applied when Apply() is called.
78+
func (sp *StatusPatch) DeleteField(key string) {
79+
delete(sp.Fields, key) // Remove from fields if it was there
80+
sp.Deletions[key] = true
81+
}
82+
83+
// AddCondition queues a condition update to be applied when Apply() is called.
84+
func (sp *StatusPatch) AddCondition(cond conditionUpdate) {
85+
sp.Conditions = append(sp.Conditions, cond)
86+
}
87+
88+
// HasChanges returns true if there are any pending changes to apply.
89+
func (sp *StatusPatch) HasChanges() bool {
90+
return len(sp.Fields) > 0 || len(sp.Conditions) > 0 || len(sp.Deletions) > 0
91+
}
92+
93+
// Apply executes all accumulated changes in a single API call.
94+
// Returns nil if there are no changes to apply.
95+
func (sp *StatusPatch) Apply() error {
96+
if !sp.HasChanges() {
97+
return nil // No changes to apply
98+
}
99+
100+
return mutateAgenticSessionStatus(sp.Namespace, sp.Name, func(status map[string]interface{}) {
101+
// Apply field deletions first
102+
for key := range sp.Deletions {
103+
delete(status, key)
104+
}
105+
106+
// Apply field updates
107+
for key, value := range sp.Fields {
108+
status[key] = value
109+
}
110+
111+
// Apply condition updates
112+
for _, cond := range sp.Conditions {
113+
setCondition(status, cond)
114+
}
115+
})
116+
}
117+
118+
// ApplyAndReset applies all changes and resets the patch for reuse.
119+
// This is useful when you need to apply changes mid-reconciliation
120+
// (e.g., before returning early) but want to continue accumulating.
121+
func (sp *StatusPatch) ApplyAndReset() error {
122+
err := sp.Apply()
123+
sp.Fields = make(map[string]interface{})
124+
sp.Conditions = make([]conditionUpdate, 0)
125+
sp.Deletions = make(map[string]bool)
126+
return err
127+
}
128+
49129
// mutateAgenticSessionStatus loads the AgenticSession, applies the mutator to the status map, and persists the result.
50130
func mutateAgenticSessionStatus(sessionNamespace, name string, mutator func(status map[string]interface{})) error {
51131
gvr := types.GetAgenticSessionResource()

0 commit comments

Comments
 (0)