Allow setting custom lookback delta for instant queries (#9946)

* Allow setting custom lookback delta for instant queries

Signed-off-by: Vilius Pranckaitis <vpranckaitis@gmail.com>
This commit is contained in:
Vilius Pranckaitis 2022-08-02 19:15:39 +10:00 committed by GitHub
parent 595d134354
commit 4660656312
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 110 additions and 7 deletions

View File

@ -128,6 +128,8 @@ type Query interface {
type QueryOpts struct {
// Enables recording per-step statistics if the engine has it enabled as well. Disabled by default.
EnablePerStepStats bool
// Lookback delta duration for this query.
LookbackDelta time.Duration
}
// query implements the Query interface.
@ -437,11 +439,17 @@ func (ng *Engine) newQuery(q storage.Queryable, opts *QueryOpts, expr parser.Exp
opts = &QueryOpts{}
}
lookbackDelta := opts.LookbackDelta
if lookbackDelta <= 0 {
lookbackDelta = ng.lookbackDelta
}
es := &parser.EvalStmt{
Expr: PreprocessExpr(expr, start, end),
Start: start,
End: end,
Interval: interval,
Expr: PreprocessExpr(expr, start, end),
Start: start,
End: end,
Interval: interval,
LookbackDelta: lookbackDelta,
}
qry := &query{
stmt: es,
@ -636,7 +644,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *parser.Eval
ctx: ctxInnerEval,
maxSamples: ng.maxSamplesPerQuery,
logger: ng.logger,
lookbackDelta: ng.lookbackDelta,
lookbackDelta: s.LookbackDelta,
samplesStats: query.sampleStats,
noStepSubqueryIntervalFn: ng.noStepSubqueryIntervalFn,
}
@ -688,7 +696,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *parser.Eval
ctx: ctxInnerEval,
maxSamples: ng.maxSamplesPerQuery,
logger: ng.logger,
lookbackDelta: ng.lookbackDelta,
lookbackDelta: s.LookbackDelta,
samplesStats: query.sampleStats,
noStepSubqueryIntervalFn: ng.noStepSubqueryIntervalFn,
}
@ -801,7 +809,7 @@ func (ng *Engine) getTimeRangesForSelector(s *parser.EvalStmt, n *parser.VectorS
}
if evalRange == 0 {
start = start - durationMilliseconds(ng.lookbackDelta)
start = start - durationMilliseconds(s.LookbackDelta)
} else {
// For all matrix queries we want to ensure that we have (end-start) + range selected
// this way we have `range` data before the start time

View File

@ -3120,3 +3120,96 @@ func TestRangeQuery(t *testing.T) {
})
}
}
func TestQueryLookbackDelta(t *testing.T) {
var (
load = `load 5m
metric 0 1 2
`
query = "metric"
lastDatapointTs = time.Unix(600, 0)
)
cases := []struct {
name string
ts time.Time
engineLookback, queryLookback time.Duration
expectSamples bool
}{
{
name: "default lookback delta",
ts: lastDatapointTs.Add(defaultLookbackDelta),
expectSamples: true,
},
{
name: "outside default lookback delta",
ts: lastDatapointTs.Add(defaultLookbackDelta + time.Millisecond),
expectSamples: false,
},
{
name: "custom engine lookback delta",
ts: lastDatapointTs.Add(10 * time.Minute),
engineLookback: 10 * time.Minute,
expectSamples: true,
},
{
name: "outside custom engine lookback delta",
ts: lastDatapointTs.Add(10*time.Minute + time.Millisecond),
engineLookback: 10 * time.Minute,
expectSamples: false,
},
{
name: "custom query lookback delta",
ts: lastDatapointTs.Add(20 * time.Minute),
engineLookback: 10 * time.Minute,
queryLookback: 20 * time.Minute,
expectSamples: true,
},
{
name: "outside custom query lookback delta",
ts: lastDatapointTs.Add(20*time.Minute + time.Millisecond),
engineLookback: 10 * time.Minute,
queryLookback: 20 * time.Minute,
expectSamples: false,
},
{
name: "negative custom query lookback delta",
ts: lastDatapointTs.Add(20 * time.Minute),
engineLookback: -10 * time.Minute,
queryLookback: 20 * time.Minute,
expectSamples: true,
},
}
for _, c := range cases {
c := c
t.Run(c.name, func(t *testing.T) {
test, err := NewTest(t, load)
require.NoError(t, err)
defer test.Close()
err = test.Run()
require.NoError(t, err)
eng := test.QueryEngine()
if c.engineLookback != 0 {
eng.lookbackDelta = c.engineLookback
}
opts := &QueryOpts{
LookbackDelta: c.queryLookback,
}
qry, err := eng.NewInstantQuery(test.Queryable(), opts, query, c.ts)
require.NoError(t, err)
res := qry.Exec(test.Context())
require.NoError(t, res.Err)
vec, ok := res.Value.(Vector)
require.True(t, ok)
if c.expectSamples {
require.NotEmpty(t, vec)
} else {
require.Empty(t, vec)
}
})
}
}

View File

@ -68,6 +68,8 @@ type EvalStmt struct {
Start, End time.Time
// Time between two evaluated instants for the range [Start:End].
Interval time.Duration
// Lookback delta to use for this evaluation.
LookbackDelta time.Duration
}
func (*EvalStmt) PromQLStmt() {}