@@ -3,15 +3,21 @@ package lib
33import (
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
1723type 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
263281func (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