@@ -18,6 +18,8 @@ import (
1818 "github.com/prometheus/client_golang/prometheus"
1919 "github.com/thanos-io/thanos/pkg/extprom"
2020 "github.com/thanos-io/thanos/pkg/gate"
21+
22+ "go.uber.org/atomic"
2123)
2224
2325// Limiter is responsible for managing the configuration and initialization of
@@ -35,6 +37,19 @@ type Limiter struct {
3537 configReloadFailedCounter prometheus.Counter
3638 receiverMode ReceiverMode
3739 configReloadTimer time.Duration
40+
41+ // Reject a request if this limit is reached.
42+ // This filed is set at the instance creation and never changes afterwards.
43+ // So it's safe to read it without a lock.
44+ maxPendingRequests int32
45+ maxPendingRequestLimitHit prometheus.Counter
46+ pendingRequests atomic.Int32
47+ pendingRequestsGauge prometheus.Gauge
48+ }
49+
50+ type LimiterOptions struct {
51+ // Value 0 disables the max pending request limiting hehavior.
52+ MaxPendingRequests int32
3853}
3954
4055// headSeriesLimiter encompasses active/head series limiting logic.
@@ -62,16 +77,50 @@ func (l *Limiter) HeadSeriesLimiter() headSeriesLimiter {
6277 return l .headSeriesLimiter
6378}
6479
80+ func (l * Limiter ) ShouldRejectNewRequest () bool {
81+ // maxPendingRequests doesn't change once set when a limiter instance is created.
82+ // So, it's safe to read it without a lock.
83+ if l .maxPendingRequests > 0 && l .pendingRequests .Load () >= l .maxPendingRequests {
84+ if l .maxPendingRequestLimitHit != nil {
85+ l .maxPendingRequestLimitHit .Inc ()
86+ }
87+ return true
88+ }
89+ newValue := l .pendingRequests .Add (1 )
90+ if l .pendingRequestsGauge != nil {
91+ l .pendingRequestsGauge .Set (float64 (newValue ))
92+ }
93+ return false
94+ }
95+
96+ func (l * Limiter ) DecrementPendingRequests () {
97+ newValue := l .pendingRequests .Add (- 1 )
98+ if l .pendingRequestsGauge != nil {
99+ l .pendingRequestsGauge .Set (float64 (newValue ))
100+ }
101+ }
102+
65103// NewLimiter creates a new *Limiter given a configuration and prometheus
66104// registerer.
67105func NewLimiter (configFile fileContent , reg prometheus.Registerer , r ReceiverMode , logger log.Logger , configReloadTimer time.Duration ) (* Limiter , error ) {
106+ return NewLimiterWithOptions (configFile , reg , r , logger , configReloadTimer , LimiterOptions {})
107+ }
108+
109+ func NewLimiterWithOptions (
110+ configFile fileContent ,
111+ reg prometheus.Registerer ,
112+ r ReceiverMode ,
113+ logger log.Logger ,
114+ configReloadTimer time.Duration ,
115+ config LimiterOptions ) (* Limiter , error ) {
68116 limiter := & Limiter {
69- writeGate : gate .NewNoop (),
70- requestLimiter : & noopRequestLimiter {},
71- headSeriesLimiter : NewNopSeriesLimit (),
72- logger : logger ,
73- receiverMode : r ,
74- configReloadTimer : configReloadTimer ,
117+ writeGate : gate .NewNoop (),
118+ requestLimiter : & noopRequestLimiter {},
119+ headSeriesLimiter : NewNopSeriesLimit (),
120+ logger : logger ,
121+ receiverMode : r ,
122+ configReloadTimer : configReloadTimer ,
123+ maxPendingRequests : config .MaxPendingRequests ,
75124 }
76125
77126 if reg != nil {
@@ -92,6 +141,26 @@ func NewLimiter(configFile fileContent, reg prometheus.Registerer, r ReceiverMod
92141 Help : "How many times the limit configuration failed to reload." ,
93142 },
94143 )
144+ limiter .configReloadFailedCounter = promauto .With (limiter .registerer ).NewCounter (
145+ prometheus.CounterOpts {
146+ Namespace : "thanos" ,
147+ Subsystem : "receive" ,
148+ Name : "limits_config_reload_err_total" ,
149+ Help : "How many times the limit configuration failed to reload." ,
150+ },
151+ )
152+ limiter .maxPendingRequestLimitHit = promauto .With (limiter .registerer ).NewCounter (
153+ prometheus.CounterOpts {
154+ Name : "thanos_receive_max_pending_write_request_limit_hit_total" ,
155+ Help : "Number of times the max pending write request limit was hit" ,
156+ },
157+ )
158+ limiter .pendingRequestsGauge = promauto .With (limiter .registerer ).NewGauge (
159+ prometheus.GaugeOpts {
160+ Name : "thanos_receive_pending_write_requests" ,
161+ Help : "Number of pending write requests" ,
162+ },
163+ )
95164 }
96165
97166 if configFile == nil {
0 commit comments