Skip to content

Commit 9871e10

Browse files
committed
fix: implement retry count handling in request routing
1 parent f06b209 commit 9871e10

1 file changed

Lines changed: 39 additions & 7 deletions

File tree

lib/queue_manager.go

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@ package lib
33
import (
44
"context"
55
"errors"
6-
lru "github.com/hashicorp/golang-lru"
7-
"github.com/hashicorp/memberlist"
8-
"github.com/sirupsen/logrus"
96
"net/http"
107
"sort"
118
"strconv"
129
"strings"
1310
"sync"
1411
"time"
12+
13+
lru "github.com/hashicorp/golang-lru"
14+
"github.com/hashicorp/memberlist"
15+
"github.com/sirupsen/logrus"
16+
)
17+
18+
const (
19+
nirnRetryCountHeader = "X-Nirn-Retry-Count"
20+
maxRetries = 2
1521
)
1622

1723
type QueueType int64
@@ -169,14 +175,26 @@ func (m *QueueManager) routeRequest(addr string, req *http.Request) (*http.Respo
169175
nodeReq, err := http.NewRequestWithContext(req.Context(), req.Method, "http://"+addr+req.URL.Path+"?"+req.URL.RawQuery, req.Body)
170176
nodeReq.Header = req.Header.Clone()
171177
nodeReq.Header.Set("nirn-routed-to", addr)
178+
179+
// Increment retry count header when routing
180+
retryCount := 0
181+
if s := req.Header.Get(nirnRetryCountHeader); s != "" {
182+
if v, err := strconv.Atoi(s); err == nil {
183+
retryCount = v
184+
}
185+
}
186+
retryCount++
187+
nodeReq.Header.Set(nirnRetryCountHeader, strconv.Itoa(retryCount))
188+
172189
if err != nil {
173190
return nil, err
174191
}
175192

176193
logger.WithFields(logrus.Fields{
177-
"to": addr,
178-
"path": req.URL.Path,
179-
"method": req.Method,
194+
"to": addr,
195+
"path": req.URL.Path,
196+
"method": req.Method,
197+
"retryCount": retryCount,
180198
}).Trace("Routing request to node in cluster")
181199
resp, err := client.Do(nodeReq)
182200
logger.WithFields(logrus.Fields{
@@ -261,11 +279,25 @@ func (m *QueueManager) getOrCreateBearerQueue(token string) (*RequestQueue, erro
261279
}
262280

263281
func (m *QueueManager) DiscordRequestHandler(resp http.ResponseWriter, req *http.Request) {
282+
// Check retry count early and fail fast to prevent infinite loops
283+
if s := req.Header.Get(nirnRetryCountHeader); s != "" {
284+
if v, err := strconv.Atoi(s); err == nil && v > maxRetries {
285+
logger.WithFields(logrus.Fields{
286+
"retryCount": v,
287+
"maxRetries": maxRetries,
288+
"path": req.URL.Path,
289+
"method": req.Method,
290+
}).Warn("Request exceeded max retry count, rejecting")
291+
Generate429(&resp)
292+
return
293+
}
294+
}
295+
264296
reqStart := time.Now()
265297
metricsPath := GetMetricsPath(req.URL.Path)
266298

267299
token := req.Header.Get("Authorization")
268-
clientId := GetBotId(token)
300+
clientId := GetBotId(token)
269301

270302
ConnectionsOpen.With(map[string]string{"route": metricsPath, "method": req.Method, "clientId": clientId}).Inc()
271303
defer ConnectionsOpen.With(map[string]string{"route": metricsPath, "method": req.Method, "clientId": clientId}).Dec()

0 commit comments

Comments
 (0)