Skip to content

Commit 7f9d028

Browse files
committed
Fix randomized controller selection logic to prevent stuck goroutines. Fixes #817
1 parent cfa350b commit 7f9d028

File tree

1 file changed

+24
-22
lines changed

1 file changed

+24
-22
lines changed

edge-apis/pool.go

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,17 @@
1717
package edge_apis
1818

1919
import (
20-
"github.com/go-openapi/runtime"
21-
"github.com/michaelquigley/pfxlog"
22-
cmap "github.com/orcaman/concurrent-map/v2"
23-
errors "github.com/pkg/errors"
2420
"math/rand/v2"
2521
"net"
2622
"net/url"
2723
"slices"
2824
"sync/atomic"
2925
"time"
26+
27+
"github.com/go-openapi/runtime"
28+
"github.com/michaelquigley/pfxlog"
29+
cmap "github.com/orcaman/concurrent-map/v2"
30+
errors "github.com/pkg/errors"
3031
)
3132

3233
type ApiClientTransport struct {
@@ -151,23 +152,14 @@ func (c *ClientTransportPoolRandom) TryTransportsForOp(operation *runtime.Client
151152
return result, err
152153
}
153154

154-
func (c *ClientTransportPoolRandom) IterateRandomTransport() <-chan *ApiClientTransport {
155-
var transportsToTry []*cmap.Tuple[string, *ApiClientTransport]
156-
for tpl := range c.pool.IterBuffered() {
157-
transportsToTry = append(transportsToTry, &tpl)
158-
}
159-
160-
ch := make(chan *ApiClientTransport, len(transportsToTry))
161-
162-
go func() {
163-
for len(transportsToTry) > 0 {
164-
var transportTpl *cmap.Tuple[string, *ApiClientTransport]
165-
transportTpl, transportsToTry = selectAndRemoveRandom(transportsToTry, nil)
166-
ch <- transportTpl.Val
167-
}
168-
}()
155+
func (c *ClientTransportPoolRandom) IterateRandomTransport() []*ApiClientTransport {
156+
var result []*ApiClientTransport
157+
c.pool.IterCb(func(_ string, v *ApiClientTransport) {
158+
result = append(result, v)
159+
})
169160

170-
return ch
161+
Randomize(result)
162+
return result
171163
}
172164

173165
func (c *ClientTransportPoolRandom) TryTransportForF(cb func(*ApiClientTransport) (any, error)) (any, error) {
@@ -200,12 +192,12 @@ func (c *ClientTransportPoolRandom) TryTransportForF(cb func(*ApiClientTransport
200192
// either no active or active failed, lets start trying them at random
201193
pfxlog.Logger().Debug("trying random transports from pool")
202194

203-
ch := c.IterateRandomTransport()
195+
transports := c.IterateRandomTransport()
204196

205197
var lastResult any
206198
lastErr := errors.New("no transports to try, active transport already failed or was nil") //default err should never be returned
207199
attempts := 0
208-
for transport := range ch {
200+
for _, transport := range transports {
209201
// skip the already attempted active key
210202
if activeKey != "" && transport.ApiUrl.String() == activeKey {
211203
continue
@@ -258,6 +250,16 @@ func errorIndicatesControllerSwap(err error) bool {
258250
return false
259251
}
260252

253+
func Randomize[T any](s []T) {
254+
for i := 0; i < len(s); i++ {
255+
idx := rand.IntN(len(s))
256+
e1 := s[i]
257+
e2 := s[idx]
258+
s[i] = e2
259+
s[idx] = e1
260+
}
261+
}
262+
261263
func selectAndRemoveRandom[T any](slice []T, zero T) (selected T, modifiedSlice []T) {
262264
if len(slice) == 0 {
263265
return zero, slice

0 commit comments

Comments
 (0)