-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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
Adapt queryTimeout to be a per-tenant configuration #6835
Changes from 6 commits
7c395b5
80c4f15
b7c01ca
f10a910
92a31ec
f3f46ab
9376341
59219f7
d891f09
b4561b9
5f9d8d3
2e4d9a5
6e10425
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,8 +64,16 @@ func NewQuerierAPI(cfg Config, querier Querier, limits *validation.Overrides, lo | |
|
||
// RangeQueryHandler is a http.HandlerFunc for range queries. | ||
func (q *QuerierAPI) RangeQueryHandler(w http.ResponseWriter, r *http.Request) { | ||
log, ctx := spanlogger.New(r.Context(), "query.RangeQuery") | ||
|
||
userID, err := tenant.TenantID(ctx) | ||
if err != nil { | ||
level.Error(log).Log("msg", "couldn't fetch tenantID", "err", err) | ||
} | ||
dannykopping marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Enforce the query timeout while querying backends | ||
ctx, cancel := context.WithDeadline(r.Context(), time.Now().Add(q.cfg.QueryTimeout)) | ||
queryTimeout := q.limits.QueryTimeout(userID) | ||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(queryTimeout)) | ||
defer cancel() | ||
|
||
request, err := loghttp.ParseRangeQuery(r) | ||
|
@@ -103,8 +111,16 @@ func (q *QuerierAPI) RangeQueryHandler(w http.ResponseWriter, r *http.Request) { | |
|
||
// InstantQueryHandler is a http.HandlerFunc for instant queries. | ||
func (q *QuerierAPI) InstantQueryHandler(w http.ResponseWriter, r *http.Request) { | ||
log, ctx := spanlogger.New(r.Context(), "query.InstantQuery") | ||
|
||
userID, err := tenant.TenantID(ctx) | ||
if err != nil { | ||
level.Error(log).Log("msg", "couldn't fetch tenantID", "err", err) | ||
dannykopping marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// Enforce the query timeout while querying backends | ||
ctx, cancel := context.WithDeadline(r.Context(), time.Now().Add(q.cfg.QueryTimeout)) | ||
queryTimeout := q.limits.QueryTimeout(userID) | ||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(queryTimeout)) | ||
defer cancel() | ||
|
||
request, err := loghttp.ParseInstantQuery(r) | ||
|
@@ -143,8 +159,15 @@ func (q *QuerierAPI) InstantQueryHandler(w http.ResponseWriter, r *http.Request) | |
|
||
// LogQueryHandler is a http.HandlerFunc for log only queries. | ||
func (q *QuerierAPI) LogQueryHandler(w http.ResponseWriter, r *http.Request) { | ||
log, ctx := spanlogger.New(r.Context(), "query.LogQuery") | ||
userID, err := tenant.TenantID(ctx) | ||
if err != nil { | ||
level.Error(log).Log("msg", "couldn't fetch tenantID", "err", err) | ||
} | ||
|
||
// Enforce the query timeout while querying backends | ||
ctx, cancel := context.WithDeadline(r.Context(), time.Now().Add(q.cfg.QueryTimeout)) | ||
queryTimeout := q.limits.QueryTimeout(userID) | ||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(queryTimeout)) | ||
defer cancel() | ||
|
||
request, err := loghttp.ParseRangeQuery(r) | ||
|
@@ -201,14 +224,23 @@ func (q *QuerierAPI) LogQueryHandler(w http.ResponseWriter, r *http.Request) { | |
|
||
// LabelHandler is a http.HandlerFunc for handling label queries. | ||
func (q *QuerierAPI) LabelHandler(w http.ResponseWriter, r *http.Request) { | ||
log, ctx := spanlogger.New(r.Context(), "query.Label") | ||
userID, err := tenant.TenantID(ctx) | ||
if err != nil { | ||
level.Error(log).Log("msg", "couldn't fetch tenantID", "err", err) | ||
} | ||
|
||
// Enforce the query timeout while querying backends | ||
queryTimeout := q.limits.QueryTimeout(userID) | ||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(queryTimeout)) | ||
defer cancel() | ||
|
||
req, err := loghttp.ParseLabelQuery(r) | ||
if err != nil { | ||
serverutil.WriteError(httpgrpc.Errorf(http.StatusBadRequest, err.Error()), w) | ||
return | ||
} | ||
|
||
log, ctx := spanlogger.New(r.Context(), "query.Label") | ||
|
||
timer := prometheus.NewTimer(logql.QueryTime.WithLabelValues("labels")) | ||
defer timer.ObserveDuration() | ||
|
||
|
@@ -376,14 +408,23 @@ func (q *QuerierAPI) TailHandler(w http.ResponseWriter, r *http.Request) { | |
// SeriesHandler returns the list of time series that match a certain label set. | ||
// See https://prometheus.io/docs/prometheus/latest/querying/api/#finding-series-by-label-matchers | ||
func (q *QuerierAPI) SeriesHandler(w http.ResponseWriter, r *http.Request) { | ||
log, ctx := spanlogger.New(r.Context(), "query.Series") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seeing it is being repeated for almost all the handler, should we make this as middleware? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm I think it shouldn't, as some handlers won't want this (ex: the tail handler) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I definitely agree about the middleware; we can apply the middleware selectively - which is already done in queryHandlers := map[string]http.Handler{
"/loki/api/v1/query_range": httpMiddleware.Wrap(http.HandlerFunc(t.querierAPI.RangeQueryHandler)),
"/loki/api/v1/query": httpMiddleware.Wrap(http.HandlerFunc(t.querierAPI.InstantQueryHandler)),
"/loki/api/v1/label": http.HandlerFunc(t.querierAPI.LabelHandler),
"/loki/api/v1/labels": http.HandlerFunc(t.querierAPI.LabelHandler),
"/loki/api/v1/label/{name}/values": http.HandlerFunc(t.querierAPI.LabelHandler),
"/loki/api/v1/series": http.HandlerFunc(t.querierAPI.SeriesHandler),
"/loki/api/v1/index/stats": http.HandlerFunc(t.querierAPI.IndexStatsHandler), |
||
userID, err := tenant.TenantID(ctx) | ||
if err != nil { | ||
level.Error(log).Log("msg", "couldn't fetch tenantID", "err", err) | ||
} | ||
|
||
// Enforce the query timeout while querying backends | ||
queryTimeout := q.limits.QueryTimeout(userID) | ||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(queryTimeout)) | ||
defer cancel() | ||
|
||
req, err := loghttp.ParseAndValidateSeriesQuery(r) | ||
if err != nil { | ||
serverutil.WriteError(httpgrpc.Errorf(http.StatusBadRequest, err.Error()), w) | ||
return | ||
} | ||
|
||
log, ctx := spanlogger.New(r.Context(), "query.Series") | ||
|
||
timer := prometheus.NewTimer(logql.QueryTime.WithLabelValues("series")) | ||
defer timer.ObserveDuration() | ||
|
||
|
@@ -422,15 +463,23 @@ func (q *QuerierAPI) SeriesHandler(w http.ResponseWriter, r *http.Request) { | |
|
||
// IndexStatsHandler queries the index for the data statistics related to a query | ||
func (q *QuerierAPI) IndexStatsHandler(w http.ResponseWriter, r *http.Request) { | ||
log, ctx := spanlogger.New(r.Context(), "query.IndexStats") | ||
userID, err := tenant.TenantID(ctx) | ||
if err != nil { | ||
level.Error(log).Log("msg", "couldn't fetch tenantID", "err", err) | ||
} | ||
|
||
// Enforce the query timeout while querying backends | ||
queryTimeout := q.limits.QueryTimeout(userID) | ||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(queryTimeout)) | ||
defer cancel() | ||
|
||
req, err := loghttp.ParseIndexStatsQuery(r) | ||
if err != nil { | ||
serverutil.WriteError(httpgrpc.Errorf(http.StatusBadRequest, err.Error()), w) | ||
return | ||
} | ||
|
||
_, ctx := spanlogger.New(r.Context(), "query.IndexStats") | ||
|
||
// TODO(owen-d): log metadata, record stats? | ||
resp, err := q.querier.IndexStats(ctx, req) | ||
if resp == nil { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think better we move this to package level const? (e.g: DefaultQueryTimeout). And Q: what's the rationale behind 2 minutes as default? (Previously query engine was using 5 * minute as default timeout. Is it to standardize it? then we may need to add it in upgrade guide as well I think)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm where did you find that the engine had 5 minutes default timeout?