diff --git a/retrieval/scheduler.go b/retrieval/scheduler.go index 062baf259..7b9a17c01 100644 --- a/retrieval/scheduler.go +++ b/retrieval/scheduler.go @@ -25,7 +25,7 @@ const ( // The base units for the exponential backoff. DEFAULT_BACKOFF_VALUE_UNIT = time.Second // The maximum allowed backoff time. - MAXIMUM_BACKOFF_VALUE = 30 * time.Minute + MAXIMUM_BACKOFF_VALUE = 2 * time.Minute ) // scheduler is an interface that various scheduling strategies must fulfill diff --git a/retrieval/target.go b/retrieval/target.go index c3354b2a6..b2875f4e0 100644 --- a/retrieval/target.go +++ b/retrieval/target.go @@ -97,7 +97,10 @@ type Target interface { // time, but it should occur no sooner than it. // // Right now, this is used as the sorting key in TargetPool. - scheduledFor() time.Time + ScheduledFor() time.Time + // EstimatedTimeToExecute emits the amount of time until the next prospective + // scheduling opportunity for this target. + EstimatedTimeToExecute() time.Duration // Return the last encountered scrape error, if any. LastError() error // The address to which the Target corresponds. Out of all of the available @@ -176,11 +179,11 @@ func (t *target) recordScrapeHealth(results chan<- *extraction.Result, timestamp } } -func (t *target) Scrape(earliest time.Time, results chan<- *extraction.Result) (err error) { +func (t *target) Scrape(earliest time.Time, results chan<- *extraction.Result) error { now := time.Now() futureState := t.state - - if err = t.scrape(now, results); err != nil { + err := t.scrape(now, results) + if err != nil { t.recordScrapeHealth(results, now, false) futureState = UNREACHABLE } else { @@ -249,23 +252,27 @@ func (t *target) scrape(timestamp time.Time, results chan<- *extraction.Result) return processor.ProcessSingle(buf, results, processOptions) } -func (t target) State() TargetState { +func (t *target) State() TargetState { return t.state } -func (t target) scheduledFor() time.Time { +func (t *target) ScheduledFor() time.Time { return t.scheduler.ScheduledFor() } -func (t target) LastError() error { +func (t *target) EstimatedTimeToExecute() time.Duration { + return t.scheduler.ScheduledFor().Sub(time.Now()) +} + +func (t *target) LastError() error { return t.lastError } -func (t target) Address() string { +func (t *target) Address() string { return t.address } -func (t target) GlobalAddress() string { +func (t *target) GlobalAddress() string { address := t.address hostname, err := os.Hostname() if err != nil { @@ -278,7 +285,7 @@ func (t target) GlobalAddress() string { return address } -func (t target) BaseLabels() clientmodel.LabelSet { +func (t *target) BaseLabels() clientmodel.LabelSet { return t.baseLabels } @@ -299,7 +306,7 @@ func (t targets) Len() int { } func (t targets) Less(i, j int) bool { - return t[i].scheduledFor().Before(t[j].scheduledFor()) + return t[i].ScheduledFor().Before(t[j].ScheduledFor()) } func (t targets) Swap(i, j int) { diff --git a/retrieval/targetmanager_test.go b/retrieval/targetmanager_test.go index e02a12140..cee692eee 100644 --- a/retrieval/targetmanager_test.go +++ b/retrieval/targetmanager_test.go @@ -66,7 +66,7 @@ func (t fakeTarget) State() TargetState { return ALIVE } -func (t *fakeTarget) scheduledFor() (time time.Time) { +func (t *fakeTarget) ScheduledFor() (time time.Time) { time = t.schedules[t.scheduleIndex] t.scheduleIndex++ diff --git a/retrieval/targetpool.go b/retrieval/targetpool.go index 0dfbc00e8..abe376a61 100644 --- a/retrieval/targetpool.go +++ b/retrieval/targetpool.go @@ -146,7 +146,7 @@ func (p *TargetPool) runIteration(results chan<- *extraction.Result, interval ti for _, target := range p.targets { now := time.Now() - if target.scheduledFor().After(now) { + if target.ScheduledFor().After(now) { // None of the remaining targets are ready to be scheduled. Signal that // we're done processing them in this scrape iteration. continue diff --git a/storage/metric/operation_test.go b/storage/metric/operation_test.go index e39cbdeb0..6a44fd4ee 100644 --- a/storage/metric/operation_test.go +++ b/storage/metric/operation_test.go @@ -1838,13 +1838,13 @@ func TestGetValueRangeAtIntervalOp(t *testing.T) { var scenarios = []struct { op getValueRangeAtIntervalOp - in model.Values - out model.Values + in Values + out Values }{ // All values before the first range. { op: testOp, - in: model.Values{ + in: Values{ { Timestamp: testInstant.Add(-4 * time.Minute), Value: 1, @@ -1854,12 +1854,12 @@ func TestGetValueRangeAtIntervalOp(t *testing.T) { Value: 2, }, }, - out: model.Values{}, + out: Values{}, }, // Values starting before first range, ending after last. { op: testOp, - in: model.Values{ + in: Values{ { Timestamp: testInstant.Add(-4 * time.Minute), Value: 1, @@ -1917,7 +1917,7 @@ func TestGetValueRangeAtIntervalOp(t *testing.T) { Value: 14, }, }, - out: model.Values{ + out: Values{ { Timestamp: testInstant.Add(-2 * time.Minute), Value: 3, @@ -1959,17 +1959,17 @@ func TestGetValueRangeAtIntervalOp(t *testing.T) { // Values starting after last range. { op: testOp, - in: model.Values{ + in: Values{ { Timestamp: testInstant.Add(21 * time.Minute), Value: 14, }, }, - out: model.Values{}, + out: Values{}, }, } for i, scenario := range scenarios { - actual := model.Values{} + actual := Values{} for !scenario.op.Consumed() { actual = append(actual, scenario.op.ExtractSamples(scenario.in)...) } diff --git a/web/templates/status.html b/web/templates/status.html index 9ec4eaee5..25656923f 100644 --- a/web/templates/status.html +++ b/web/templates/status.html @@ -40,23 +40,43 @@

Targets

-

Curation