diff options
author | Will Chandler <wchandler@gitlab.com> | 2022-07-20 22:59:55 +0300 |
---|---|---|
committer | Will Chandler <wchandler@gitlab.com> | 2022-07-20 23:28:36 +0300 |
commit | 87fd90773546bfb61a7848241de38dabd1c01105 (patch) | |
tree | 24c6e4ae8bd93b94c9823e12420d0f52c4ee998c | |
parent | c8e917da08bf4a0de47ac79f3e630327492eea4b (diff) |
limithandler: Wrap errors in ResourceExhaustedwc-limit-exhausted
Currently we return `codes.Unavailable` when a request has been
terminated due to the concurrency/rate limiter. However, this code is
also returned when Gitaly is completely down, so all of our clients
(shell, workhorse, rails) return a hard-coded message to contact site
administrators to users when this code is returned.
Looking at how Google Cloud uses this code[0], it's treated as the
equivalent of an HTTP 503. `codes.ResourceExhausted` is the equivalent
of a 429, which is returned when a request has been rate limited.
Let's switch the concurrency limiter to wrap its errors in
`ResourceExhausted` to bring our code usage in line with common
practices and to save our clients from trying to parse the error message
to determine if Gitaly is up.
[0]: https://cloud.google.com/apis/design/errors
Changelog: changed
-rw-r--r-- | internal/middleware/limithandler/concurrency_limiter.go | 8 | ||||
-rw-r--r-- | internal/middleware/limithandler/middleware_test.go | 2 | ||||
-rw-r--r-- | internal/middleware/limithandler/rate_limiter.go | 2 |
3 files changed, 6 insertions, 6 deletions
diff --git a/internal/middleware/limithandler/concurrency_limiter.go b/internal/middleware/limithandler/concurrency_limiter.go index e2595571b..58396d3e2 100644 --- a/internal/middleware/limithandler/concurrency_limiter.go +++ b/internal/middleware/limithandler/concurrency_limiter.go @@ -150,7 +150,7 @@ func (c *ConcurrencyLimiter) Limit(ctx context.Context, lockKey string, f Limite if err := c.queueInc(ctx); err != nil { if errors.Is(err, ErrMaxQueueSize) { detailedErr, errGeneratingDetailedErr := helper.ErrWithDetails( - helper.ErrUnavailable(ErrMaxQueueSize), + helper.ErrResourceExhausted(ErrMaxQueueSize), &gitalypb.LimitError{ ErrorMessage: err.Error(), RetryAfter: durationpb.New(0), @@ -161,7 +161,7 @@ func (c *ConcurrencyLimiter) Limit(ctx context.Context, lockKey string, f Limite WithError(errGeneratingDetailedErr). Error("failed to generate detailed error") - return nil, helper.ErrUnavailable(ErrMaxQueueSize) + return nil, helper.ErrResourceExhausted(ErrMaxQueueSize) } return nil, detailedErr @@ -186,7 +186,7 @@ func (c *ConcurrencyLimiter) Limit(ctx context.Context, lockKey string, f Limite c.monitor.Dropped(ctx, "max_time") detailedErr, errGeneratingDetailedErr := helper.ErrWithDetails( - helper.ErrUnavailable(ErrMaxQueueTime), + helper.ErrResourceExhausted(ErrMaxQueueTime), &gitalypb.LimitError{ ErrorMessage: err.Error(), RetryAfter: durationpb.New(0), @@ -197,7 +197,7 @@ func (c *ConcurrencyLimiter) Limit(ctx context.Context, lockKey string, f Limite WithError(errGeneratingDetailedErr). Error("failed to generate detailed error") - return nil, helper.ErrUnavailable(ErrMaxQueueTime) + return nil, helper.ErrResourceExhausted(ErrMaxQueueTime) } return nil, detailedErr diff --git a/internal/middleware/limithandler/middleware_test.go b/internal/middleware/limithandler/middleware_test.go index c929d19ea..d9a38682d 100644 --- a/internal/middleware/limithandler/middleware_test.go +++ b/internal/middleware/limithandler/middleware_test.go @@ -336,7 +336,7 @@ func TestStreamLimitHandler_error(t *testing.T) { } err := <-errChan - testhelper.RequireGrpcCode(t, err, codes.Unavailable) + testhelper.RequireGrpcCode(t, err, codes.ResourceExhausted) // ensure it is a structured error st, ok := status.FromError(err) require.True(t, ok) diff --git a/internal/middleware/limithandler/rate_limiter.go b/internal/middleware/limithandler/rate_limiter.go index 63124b0d7..57db2acaa 100644 --- a/internal/middleware/limithandler/rate_limiter.go +++ b/internal/middleware/limithandler/rate_limiter.go @@ -44,7 +44,7 @@ func (r *RateLimiter) Limit(ctx context.Context, lockKey string, f LimitedFunc) // of traffic. r.requestsDroppedMetric.Inc() if featureflag.RateLimit.IsEnabled(ctx) { - err := helper.ErrUnavailable(ErrRateLimit) + err := helper.ErrResourceExhausted(ErrRateLimit) detailedErr, errGeneratingDetailedErr := helper.ErrWithDetails( err, |