Skip to content

Commit a605e63

Browse files
gongna-augongna-au
andauthored
feat(kbagent): implement request-level timeout override and retry for action execution (#10158)
Co-authored-by: gongna-au <gongna1@xiaomi.com>
1 parent 237b1d0 commit a605e63

2 files changed

Lines changed: 38 additions & 6 deletions

File tree

pkg/kbagent/proto/proto.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ type ActionRequest struct {
7474
Action string `json:"action"`
7575
Parameters map[string]string `json:"parameters,omitempty"`
7676
NonBlocking *bool `json:"nonBlocking,omitempty"`
77-
TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty"` // TODO: not implemented
78-
RetryPolicy *RetryPolicy `json:"retryPolicy,omitempty"` // TODO: not implemented
77+
TimeoutSeconds *int32 `json:"timeoutSeconds,omitempty"`
78+
RetryPolicy *RetryPolicy `json:"retryPolicy,omitempty"`
7979
}
8080

8181
type ActionResponse struct {

pkg/kbagent/service/action.go

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"net"
2727
"strings"
2828
"sync"
29+
"time"
2930

3031
"github.com/go-logr/logr"
3132
"github.com/pkg/errors"
@@ -124,19 +125,20 @@ func (s *actionService) handleRequest(ctx context.Context, req *proto.ActionRequ
124125
if err := checkReconfigure(ctx, req); err != nil {
125126
return nil, err
126127
}
128+
timeout := resolveTimeout(&action.TimeoutSeconds, req.TimeoutSeconds)
127129
if req.NonBlocking == nil || !*req.NonBlocking {
128-
return blockingCallAction(ctx, action, req.Parameters, &action.TimeoutSeconds)
130+
return callActionWithRetry(ctx, action, req.Parameters, timeout, req.RetryPolicy)
129131
}
130-
return s.handleRequestNonBlocking(ctx, req, action)
132+
return s.handleRequestNonBlocking(ctx, req, action, timeout)
131133
}
132134

133-
func (s *actionService) handleRequestNonBlocking(ctx context.Context, req *proto.ActionRequest, action *proto.Action) ([]byte, error) {
135+
func (s *actionService) handleRequestNonBlocking(ctx context.Context, req *proto.ActionRequest, action *proto.Action, timeout *int32) ([]byte, error) {
134136
s.mutex.Lock()
135137
defer s.mutex.Unlock()
136138

137139
running, ok := s.runningActions[req.Action]
138140
if !ok {
139-
resultChan, err := nonBlockingCallAction(ctx, action, req.Parameters, &action.TimeoutSeconds)
141+
resultChan, err := nonBlockingCallAction(ctx, action, req.Parameters, timeout)
140142
if err != nil {
141143
return nil, err
142144
}
@@ -155,3 +157,33 @@ func (s *actionService) handleRequestNonBlocking(ctx context.Context, req *proto
155157
}
156158
return (*result).stdout.Bytes(), nil
157159
}
160+
161+
func resolveTimeout(actionTimeout *int32, requestTimeout *int32) *int32 {
162+
if requestTimeout != nil {
163+
return requestTimeout
164+
}
165+
return actionTimeout
166+
}
167+
168+
func callActionWithRetry(ctx context.Context, action *proto.Action, parameters map[string]string, timeout *int32, retryPolicy *proto.RetryPolicy) ([]byte, error) {
169+
output, err := blockingCallAction(ctx, action, parameters, timeout)
170+
if err == nil || retryPolicy == nil || retryPolicy.MaxRetries <= 0 {
171+
return output, err
172+
}
173+
174+
interval := retryPolicy.RetryInterval
175+
for i := 0; i < retryPolicy.MaxRetries; i++ {
176+
if interval > 0 {
177+
select {
178+
case <-ctx.Done():
179+
return nil, ctx.Err()
180+
case <-time.After(interval):
181+
}
182+
}
183+
output, err = blockingCallAction(ctx, action, parameters, timeout)
184+
if err == nil {
185+
return output, nil
186+
}
187+
}
188+
return output, err
189+
}

0 commit comments

Comments
 (0)