Skip to content

Commit 4b0ba32

Browse files
Copilotlpcox
andauthored
Address code review: fix transport error handling, header casing, import grouping
Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/29c289a0-52c0-4c27-98f3-8eef3b574559 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
1 parent 99dea91 commit 4b0ba32

4 files changed

Lines changed: 12 additions & 7 deletions

File tree

internal/config/rate_limit_config_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package config
22

33
import (
4+
"testing"
5+
46
"github.com/stretchr/testify/assert"
57
"github.com/stretchr/testify/require"
6-
"testing"
78
)
89

910
func TestServerConfig_RateLimitFields(t *testing.T) {

internal/proxy/handler.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -422,13 +422,15 @@ func copyResponseHeaders(w http.ResponseWriter, resp *http.Response) {
422422
}
423423

424424
// injectRetryAfterIfRateLimited inspects the upstream response for rate-limit signals
425-
// (HTTP 429 or X-RateLimit-Remaining == 0). When detected it:
425+
// (HTTP 429 or X-Ratelimit-Remaining == 0). When detected it:
426426
// 1. Injects a Retry-After header so the client knows when to retry.
427427
// 2. Logs the event at ERROR level so operators can monitor rate-limit incidents.
428428
func injectRetryAfterIfRateLimited(w http.ResponseWriter, resp *http.Response) {
429429
is429 := resp.StatusCode == http.StatusTooManyRequests
430-
remaining := resp.Header.Get("X-RateLimit-Remaining")
431-
resetHeader := resp.Header.Get("X-RateLimit-Reset")
430+
// Use Go's canonical header key form (textproto.CanonicalMIMEHeaderKey produces
431+
// "X-Ratelimit-Remaining", matching GitHub's actual response headers).
432+
remaining := resp.Header.Get("X-Ratelimit-Remaining")
433+
resetHeader := resp.Header.Get("X-Ratelimit-Reset")
432434

433435
isRateLimited := is429 || remaining == "0"
434436
if !isRateLimited {
@@ -441,7 +443,7 @@ func injectRetryAfterIfRateLimited(w http.ResponseWriter, resp *http.Response) {
441443
w.Header().Set("Retry-After", strconv.Itoa(retryAfter))
442444

443445
logger.LogError("client",
444-
"upstream rate limit hit: status=%d X-RateLimit-Remaining=%s X-RateLimit-Reset=%s retry-after=%ds",
446+
"upstream rate limit hit: status=%d X-Ratelimit-Remaining=%s X-Ratelimit-Reset=%s retry-after=%ds",
445447
resp.StatusCode, remaining, resetHeader, retryAfter)
446448
}
447449

internal/proxy/rate_limit_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func TestInjectRetryAfterIfRateLimited(t *testing.T) {
3333
assert.Greater(t, secs, 0, "Retry-After should be positive")
3434
})
3535

36-
t.Run("X-RateLimit-Remaining 0 injects Retry-After", func(t *testing.T) {
36+
t.Run("X-Ratelimit-Remaining 0 injects Retry-After", func(t *testing.T) {
3737
t.Parallel()
3838
w := httptest.NewRecorder()
3939
future := time.Now().Add(60 * time.Second)

internal/server/unified.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,9 @@ func (us *UnifiedServer) callBackendTool(ctx context.Context, serverID, toolName
574574

575575
backendResult, err := executeBackendToolCall(execCtx, us.launcher, serverID, sessionID, toolName, args)
576576
if err != nil {
577-
cb.RecordSuccess() // transport error ≠ rate limit; reset consecutive counter
577+
// Transport errors (connection failure, JSON parse error, etc.) are not rate-limit
578+
// events and must not affect the consecutive rate-limit counter. Leave the circuit
579+
// breaker state unchanged so genuine rate-limit history is preserved.
578580
execSpan.RecordError(err)
579581
execSpan.SetStatus(codes.Error, err.Error())
580582
httpStatusCode = 500

0 commit comments

Comments
 (0)