Skip to content

Add ResourceMonitor module in Cortex, and add ResourceBasedLimiter in Ingesters and StoreGateways #6674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
Apr 18, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
80b2d5c
Add resource based throttling to ingesters and store gateways
justinjung04 Mar 25, 2025
2121845
doc
justinjung04 Mar 25, 2025
2b168fc
Add automaxprocs
justinjung04 Mar 25, 2025
56f8e57
nit
justinjung04 Mar 25, 2025
9efbbd9
Add test for monitor
justinjung04 Mar 26, 2025
30bbd3d
fix tests
justinjung04 Mar 26, 2025
fa56e65
changelog
justinjung04 Mar 26, 2025
a2ffcdd
Merge branch 'master' into resource-based-throttling
justinjung04 Mar 26, 2025
5cccd60
fix test
justinjung04 Mar 26, 2025
6e37330
remove interface
justinjung04 Mar 26, 2025
08a6adf
address comments
justinjung04 Mar 31, 2025
067478b
rename doc
justinjung04 Mar 31, 2025
18fdf37
Make monitor more generic + separate scanners
justinjung04 Apr 10, 2025
aa81155
fix tests
justinjung04 Apr 10, 2025
a528a7a
fix more tests
justinjung04 Apr 10, 2025
42e52b3
remove monitor_test.go
justinjung04 Apr 10, 2025
50993e1
move noop scanner to darwin scanner
justinjung04 Apr 10, 2025
e56431e
doc update
justinjung04 Apr 10, 2025
eae4df7
doc
justinjung04 Apr 10, 2025
fd19f5c
lint
justinjung04 Apr 10, 2025
f588d94
add debugging log on unsupported resource type
justinjung04 Apr 10, 2025
6138a9d
test
justinjung04 Apr 10, 2025
7bd7ab9
add more error handling + resource_based_limiter_limit metric
justinjung04 Apr 10, 2025
6da53e9
fix test
justinjung04 Apr 10, 2025
a8d4218
fix test
justinjung04 Apr 10, 2025
d6d3839
update changelog
justinjung04 Apr 10, 2025
c68bbd2
Move noopScanner to scanner.go and fix RegisterFlagsWithPrefix
justinjung04 Apr 15, 2025
025a93a
Add limit breached metric + wrap error with 429
justinjung04 Apr 16, 2025
6ffef63
Add more validation and test on instance_limits
justinjung04 Apr 16, 2025
7808940
Added _total to counter metric
justinjung04 Apr 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* [FEATURE] Query Frontend: Add dynamic interval size for query splitting. This is enabled by configuring experimental flags `querier.max-shards-per-query` and/or `querier.max-fetched-data-duration-per-query`. The split interval size is dynamically increased to maintain a number of shards and total duration fetched below the configured values. #6458
* [FEATURE] Querier/Ruler: Add `query_partial_data` and `rules_partial_data` limits to allow queries/rules to be evaluated with data from a single zone, if other zones are not available. #6526
* [FEATURE] Update prometheus alertmanager version to v0.28.0 and add new integration msteamsv2, jira, and rocketchat. #6590
* [FEATURE] Ingester: Add a `-ingester.enable-ooo-native-histograms` flag to enable out-of-order native histogram ingestion per tenant. It only takes effect when `-blocks-storage.tsdb.enable-native-histograms=true` and `-ingester.out-of-order-time-window` > 0. It is applied after the restart if it is changed at runtime through the runtime config. #6626
* [FEATURE] Ingester/StoreGateway: Add `resource-thresholds` in ingesters and store gateways to throttle query requests when the pods are under resource pressure. #6674
* [FEATURE] Ingester: Support out-of-order native histogram ingestion. It automatically enabled when `-ingester.out-of-order-time-window > 0` and `-blocks-storage.tsdb.enable-native-histograms=true`. #6626 #6663
* [ENHANCEMENT] Alertmanager: Add nflog and silences maintenance metrics. #6659
* [ENHANCEMENT] Querier: limit label APIs to query only ingesters if `start` param is not been specified. #6618
Expand Down
1 change: 1 addition & 0 deletions cmd/cortex/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
collectorversion "github.com/prometheus/client_golang/prometheus/collectors/version"
"github.com/prometheus/common/version"
_ "go.uber.org/automaxprocs"
"gopkg.in/yaml.v2"

"github.com/cortexproject/cortex/pkg/cortex"
Expand Down
9 changes: 9 additions & 0 deletions docs/configuration/config-file-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,15 @@ query_scheduler:
# CLI flag: -query-scheduler.grpc-client-config.connect-timeout
[connect_timeout: <duration> | default = 5s]

resource_thresholds:
# Utilization threshold for CPU in percentage, between 0 and 1. 0 to disable.
# CLI flag: -resource-thresholds.cpu
[cpu: <float> | default = 0]

# Utilization threshold for heap in percentage, between 0 and 1. 0 to disable.
# CLI flag: -resource-thresholds.heap
[heap: <float> | default = 0]

# The tracing_config configures backends cortex uses.
[tracing: <tracing_config>]
```
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,11 @@ require (
github.com/google/go-cmp v0.7.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822
github.com/prometheus/procfs v0.15.1
github.com/sercand/kuberesolver/v5 v5.1.1
github.com/tjhop/slog-gokit v0.1.2
go.opentelemetry.io/collector/pdata v1.24.0
go.uber.org/automaxprocs v1.6.0
google.golang.org/protobuf v1.36.4
)

Expand Down Expand Up @@ -199,7 +201,6 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus-community/prom-label-proxy v0.8.1-0.20240127162815-c1195f9aabc0 // indirect
github.com/prometheus/exporter-toolkit v0.13.2 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/prometheus/sigv4 v0.1.1 // indirect
github.com/redis/rueidis v1.0.45-alpha.1 // indirect
github.com/rs/cors v1.11.1 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1560,6 +1560,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus-community/prom-label-proxy v0.8.1-0.20240127162815-c1195f9aabc0 h1:owfYHh79h8Y5HvNMGyww+DaVwo10CKiRW1RQrrZzIwg=
github.com/prometheus-community/prom-label-proxy v0.8.1-0.20240127162815-c1195f9aabc0/go.mod h1:rT989D4UtOcfd9tVqIZRVIM8rkg+9XbreBjFNEKXvVI=
github.com/prometheus/alertmanager v0.28.1 h1:BK5pCoAtaKg01BYRUJhEDV1tqJMEtYBGzPw8QdvnnvA=
Expand Down Expand Up @@ -1811,6 +1813,8 @@ go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
Expand Down
26 changes: 26 additions & 0 deletions pkg/configs/resources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package configs

import (
"errors"
"flag"
)

var ErrInvalidResourceThreshold = errors.New("invalid resource utilization threshold, it must be between 0 and 1")

type Resources struct {
CPU float64 `yaml:"cpu"`
Heap float64 `yaml:"heap"`
}

func (cfg *Resources) RegisterFlags(f *flag.FlagSet) {
f.Float64Var(&cfg.CPU, "resource-thresholds.cpu", 0, "Utilization threshold for CPU in percentage, between 0 and 1. 0 to disable.")
f.Float64Var(&cfg.Heap, "resource-thresholds.heap", 0, "Utilization threshold for heap in percentage, between 0 and 1. 0 to disable.")
}

func (cfg *Resources) Validate() error {
if cfg.CPU > 1 || cfg.CPU < 0 || cfg.Heap > 1 || cfg.Heap < 0 {
return ErrInvalidResourceThreshold
}

return nil
}
8 changes: 8 additions & 0 deletions pkg/cortex/cortex.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"gopkg.in/yaml.v2"

"github.com/cortexproject/cortex/pkg/util/grpcclient"
"github.com/cortexproject/cortex/pkg/util/resource"

"github.com/cortexproject/cortex/pkg/alertmanager"
"github.com/cortexproject/cortex/pkg/alertmanager/alertstore"
Expand Down Expand Up @@ -122,6 +123,7 @@ type Config struct {
RuntimeConfig runtimeconfig.Config `yaml:"runtime_config"`
MemberlistKV memberlist.KVConfig `yaml:"memberlist"`
QueryScheduler scheduler.Config `yaml:"query_scheduler"`
ResourceThresholds configs.Resources `yaml:"resource_thresholds"`

Tracing tracing.Config `yaml:"tracing"`
}
Expand Down Expand Up @@ -170,6 +172,7 @@ func (c *Config) RegisterFlags(f *flag.FlagSet) {
c.MemberlistKV.RegisterFlags(f)
c.QueryScheduler.RegisterFlags(f)
c.Tracing.RegisterFlags(f)
c.ResourceThresholds.RegisterFlags(f)
}

// Validate the cortex config and returns an error if the validation
Expand Down Expand Up @@ -237,6 +240,10 @@ func (c *Config) Validate(log log.Logger) error {
return errors.Wrap(err, "invalid tracing config")
}

if err := c.ResourceThresholds.Validate(); err != nil {
return errors.Wrap(err, "invalid resource_thresholds config")
}

return nil
}

Expand Down Expand Up @@ -315,6 +322,7 @@ type Cortex struct {
MetadataQuerier querier.MetadataQuerier
QuerierEngine promql.QueryEngine
QueryFrontendTripperware tripperware.Tripperware
ResourceMonitor *resource.Monitor

Ruler *ruler.Ruler
RulerStorage rulestore.RuleStore
Expand Down
12 changes: 11 additions & 1 deletion pkg/cortex/cortex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"github.com/cortexproject/cortex/pkg/alertmanager"
"github.com/cortexproject/cortex/pkg/alertmanager/alertstore"
"github.com/cortexproject/cortex/pkg/configs"
"github.com/cortexproject/cortex/pkg/cortex/storage"
"github.com/cortexproject/cortex/pkg/frontend/v1/frontendv1pb"
"github.com/cortexproject/cortex/pkg/ingester"
Expand Down Expand Up @@ -165,11 +166,20 @@ func TestConfigValidation(t *testing.T) {
},
expectedError: errInvalidHTTPPrefix,
},
{
name: "should fail validation for resource thresholds",
getTestConfig: func() *Config {
configuration := newDefaultConfig()
configuration.ResourceThresholds.CPU = 10
return configuration
},
expectedError: configs.ErrInvalidResourceThreshold,
},
} {
t.Run(tc.name, func(t *testing.T) {
err := tc.getTestConfig().Validate(nil)
if tc.expectedError != nil {
require.Equal(t, tc.expectedError, err)
require.ErrorContains(t, err, tc.expectedError.Error())
} else {
require.NoError(t, err)
}
Expand Down
34 changes: 30 additions & 4 deletions pkg/cortex/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"fmt"
"log/slog"
"net/http"
"runtime"
"runtime/debug"

"github.com/go-kit/log/level"
"github.com/opentracing-contrib/go-stdlib/nethttp"
Expand All @@ -27,6 +29,7 @@ import (
"github.com/cortexproject/cortex/pkg/alertmanager/alertstore"
"github.com/cortexproject/cortex/pkg/api"
"github.com/cortexproject/cortex/pkg/compactor"
"github.com/cortexproject/cortex/pkg/configs"
configAPI "github.com/cortexproject/cortex/pkg/configs/api"
"github.com/cortexproject/cortex/pkg/configs/db"
"github.com/cortexproject/cortex/pkg/distributor"
Expand All @@ -51,6 +54,7 @@ import (
"github.com/cortexproject/cortex/pkg/util/grpcclient"
util_log "github.com/cortexproject/cortex/pkg/util/log"
"github.com/cortexproject/cortex/pkg/util/modules"
"github.com/cortexproject/cortex/pkg/util/resource"
"github.com/cortexproject/cortex/pkg/util/runtimeconfig"
"github.com/cortexproject/cortex/pkg/util/services"
"github.com/cortexproject/cortex/pkg/util/validation"
Expand Down Expand Up @@ -86,6 +90,7 @@ const (
Purger string = "purger"
QueryScheduler string = "query-scheduler"
TenantFederation string = "tenant-federation"
ResourceMonitor string = "resource-monitor"
All string = "all"
)

Expand Down Expand Up @@ -441,7 +446,7 @@ func (t *Cortex) initIngesterService() (serv services.Service, err error) {
t.Cfg.Ingester.QueryIngestersWithin = t.Cfg.Querier.QueryIngestersWithin
t.tsdbIngesterConfig()

t.Ingester, err = ingester.New(t.Cfg.Ingester, t.Overrides, prometheus.DefaultRegisterer, util_log.Logger)
t.Ingester, err = ingester.New(t.Cfg.Ingester, t.Overrides, prometheus.DefaultRegisterer, util_log.Logger, t.ResourceMonitor)
if err != nil {
return
}
Expand Down Expand Up @@ -705,7 +710,7 @@ func (t *Cortex) initCompactor() (serv services.Service, err error) {
func (t *Cortex) initStoreGateway() (serv services.Service, err error) {
t.Cfg.StoreGateway.ShardingRing.ListenPort = t.Cfg.Server.GRPCListenPort

t.StoreGateway, err = storegateway.NewStoreGateway(t.Cfg.StoreGateway, t.Cfg.BlocksStorage, t.Overrides, t.Cfg.Server.LogLevel, util_log.Logger, prometheus.DefaultRegisterer)
t.StoreGateway, err = storegateway.NewStoreGateway(t.Cfg.StoreGateway, t.Cfg.BlocksStorage, t.Overrides, t.Cfg.Server.LogLevel, util_log.Logger, prometheus.DefaultRegisterer, t.ResourceMonitor)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -765,11 +770,32 @@ func (t *Cortex) initQueryScheduler() (services.Service, error) {
return s, nil
}

func (t *Cortex) initResourceMonitor() (services.Service, error) {
if t.Cfg.ResourceThresholds.CPU <= 0 && t.Cfg.ResourceThresholds.Heap <= 0 {
return nil, nil
}

scanner, err := resource.NewScanner()
if err != nil {
return nil, err
}

limits := configs.Resources{
CPU: float64(runtime.GOMAXPROCS(0)),
Heap: float64(debug.SetMemoryLimit(-1)),
}

t.ResourceMonitor, err = resource.NewMonitor(t.Cfg.ResourceThresholds, limits, scanner, prometheus.DefaultRegisterer)

return t.ResourceMonitor, err
}

func (t *Cortex) setupModuleManager() error {
mm := modules.NewManager(util_log.Logger)

// Register all modules here.
// RegisterModule(name string, initFn func()(services.Service, error))
mm.RegisterModule(ResourceMonitor, t.initResourceMonitor)
mm.RegisterModule(Server, t.initServer, modules.UserInvisibleModule)
mm.RegisterModule(API, t.initAPI, modules.UserInvisibleModule)
mm.RegisterModule(RuntimeConfig, t.initRuntimeConfig, modules.UserInvisibleModule)
Expand Down Expand Up @@ -811,7 +837,7 @@ func (t *Cortex) setupModuleManager() error {
Distributor: {DistributorService, API, GrpcClientService},
DistributorService: {Ring, Overrides},
Ingester: {IngesterService, Overrides, API},
IngesterService: {Overrides, RuntimeConfig, MemberlistKV},
IngesterService: {Overrides, RuntimeConfig, MemberlistKV, ResourceMonitor},
Flusher: {Overrides, API},
Queryable: {Overrides, DistributorService, Overrides, Ring, API, StoreQueryable, MemberlistKV},
Querier: {TenantFederation},
Expand All @@ -824,7 +850,7 @@ func (t *Cortex) setupModuleManager() error {
Configs: {API},
AlertManager: {API, MemberlistKV, Overrides},
Compactor: {API, MemberlistKV, Overrides},
StoreGateway: {API, Overrides, MemberlistKV},
StoreGateway: {API, Overrides, MemberlistKV, ResourceMonitor},
TenantDeletion: {API, Overrides},
Purger: {TenantDeletion},
TenantFederation: {Queryable},
Expand Down
54 changes: 32 additions & 22 deletions pkg/frontend/transport/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/cortexproject/cortex/pkg/util"
util_api "github.com/cortexproject/cortex/pkg/util/api"
util_log "github.com/cortexproject/cortex/pkg/util/log"
"github.com/cortexproject/cortex/pkg/util/resource"
)

const (
Expand All @@ -49,6 +50,7 @@ const (
reasonRequestBodySizeExceeded = "request_body_size_exceeded"
reasonResponseBodySizeExceeded = "response_body_size_exceeded"
reasonTooManyRequests = "too_many_requests"
reasonResourceExhausted = "resource_exhausted"
reasonTimeRangeExceeded = "time_range_exceeded"
reasonTooManySamples = "too_many_samples"
reasonSeriesFetched = "series_fetched"
Expand Down Expand Up @@ -489,30 +491,38 @@ func (f *Handler) reportQueryStats(r *http.Request, source, userID string, query
}

var reason string
if statusCode == http.StatusTooManyRequests {
reason = reasonTooManyRequests
} else if statusCode == http.StatusRequestEntityTooLarge {
if statusCode == http.StatusRequestEntityTooLarge {
reason = reasonResponseBodySizeExceeded
} else if statusCode == http.StatusUnprocessableEntity {
} else if error != nil {
// We are unable to use errors.As to compare since body string from the http response is wrapped as an error
errMsg := error.Error()
if strings.Contains(errMsg, limitTooManySamples) {
reason = reasonTooManySamples
} else if strings.Contains(errMsg, limitTimeRangeExceeded) {
reason = reasonTimeRangeExceeded
} else if strings.Contains(errMsg, limitSeriesFetched) {
reason = reasonSeriesFetched
} else if strings.Contains(errMsg, limitChunksFetched) {
reason = reasonChunksFetched
} else if strings.Contains(errMsg, limitChunkBytesFetched) {
reason = reasonChunkBytesFetched
} else if strings.Contains(errMsg, limitDataBytesFetched) {
reason = reasonDataBytesFetched
} else if strings.Contains(errMsg, limitSeriesStoreGateway) {
reason = reasonSeriesLimitStoreGateway
} else if strings.Contains(errMsg, limitChunksStoreGateway) {
reason = reasonChunksLimitStoreGateway
} else if strings.Contains(errMsg, limitBytesStoreGateway) {
reason = reasonBytesLimitStoreGateway
if statusCode == http.StatusTooManyRequests {
var resourceExhaustedErr resource.ExhaustedError
if strings.Contains(errMsg, resourceExhaustedErr.Error()) {
reason = reasonResourceExhausted
} else {
reason = reasonTooManyRequests
}
} else if statusCode == http.StatusUnprocessableEntity {
if strings.Contains(errMsg, limitTooManySamples) {
reason = reasonTooManySamples
} else if strings.Contains(errMsg, limitTimeRangeExceeded) {
reason = reasonTimeRangeExceeded
} else if strings.Contains(errMsg, limitSeriesFetched) {
reason = reasonSeriesFetched
} else if strings.Contains(errMsg, limitChunksFetched) {
reason = reasonChunksFetched
} else if strings.Contains(errMsg, limitChunkBytesFetched) {
reason = reasonChunkBytesFetched
} else if strings.Contains(errMsg, limitDataBytesFetched) {
reason = reasonDataBytesFetched
} else if strings.Contains(errMsg, limitSeriesStoreGateway) {
reason = reasonSeriesLimitStoreGateway
} else if strings.Contains(errMsg, limitChunksStoreGateway) {
reason = reasonChunksLimitStoreGateway
} else if strings.Contains(errMsg, limitBytesStoreGateway) {
reason = reasonBytesLimitStoreGateway
}
}
}
if len(reason) > 0 {
Expand Down
18 changes: 18 additions & 0 deletions pkg/frontend/transport/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/cortexproject/cortex/pkg/tenant"
util_api "github.com/cortexproject/cortex/pkg/util/api"
util_log "github.com/cortexproject/cortex/pkg/util/log"
"github.com/cortexproject/cortex/pkg/util/resource"
)

type roundTripperFunc func(*http.Request) (*http.Response, error)
Expand Down Expand Up @@ -380,6 +381,23 @@ func TestHandler_ServeHTTP(t *testing.T) {
},
expectedStatusCode: http.StatusUnprocessableEntity,
},
{
name: "test handler with reasonResourceExhausted",
cfg: HandlerConfig{QueryStatsEnabled: true},
expectedMetrics: 6,
roundTripperFunc: roundTripperFunc(func(req *http.Request) (*http.Response, error) {
resourceExhaustedErr := &resource.ExhaustedError{}
return &http.Response{
StatusCode: http.StatusTooManyRequests,
Body: io.NopCloser(strings.NewReader(resourceExhaustedErr.Error())),
}, nil
}),
additionalMetricsCheckFunc: func(h *Handler) {
v := promtest.ToFloat64(h.rejectedQueries.WithLabelValues(reasonResourceExhausted, tripperware.SourceAPI, userID))
assert.Equal(t, float64(1), v)
},
expectedStatusCode: http.StatusTooManyRequests,
},
} {
t.Run(tt.name, func(t *testing.T) {
reg := prometheus.NewPedanticRegistry()
Expand Down
Loading
Loading