mirror of
				https://github.com/prometheus/prometheus.git
				synced 2025-11-04 02:11:01 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			119 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2013 Prometheus Team
 | 
						|
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
// you may not use this file except in compliance with the License.
 | 
						|
// You may obtain a copy of the License at
 | 
						|
//
 | 
						|
// http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, software
 | 
						|
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
// See the License for the specific language governing permissions and
 | 
						|
// limitations under the License.
 | 
						|
 | 
						|
package retrieval
 | 
						|
 | 
						|
import (
 | 
						|
	"github.com/prometheus/prometheus/utility"
 | 
						|
	"math"
 | 
						|
	"time"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	// The default increment for exponential backoff when querying a target.
 | 
						|
	DEFAULT_BACKOFF_VALUE = 2
 | 
						|
	// The base units for the exponential backoff.
 | 
						|
	DEFAULT_BACKOFF_VALUE_UNIT = time.Second
 | 
						|
	// The maximum allowed backoff time.
 | 
						|
	MAXIMUM_BACKOFF_VALUE = 30 * time.Minute
 | 
						|
)
 | 
						|
 | 
						|
// scheduler is an interface that various scheduling strategies must fulfill
 | 
						|
// in order to set the scheduling order for a target.
 | 
						|
//
 | 
						|
// Target takes advantage of this type by embedding an instance of scheduler
 | 
						|
// in each Target instance itself.  The emitted scheduler.ScheduledFor() is
 | 
						|
// the basis for sorting the order of pending queries.
 | 
						|
//
 | 
						|
// This type is described as an interface to maximize testability.
 | 
						|
type scheduler interface {
 | 
						|
	// ScheduledFor emits the earliest time at which the given object is allowed
 | 
						|
	// to be run.  This time may or not be a reflection of the earliest parameter
 | 
						|
	// provided in Reschedule; that is up to the underlying strategy
 | 
						|
	// implementations.
 | 
						|
	ScheduledFor() time.Time
 | 
						|
	// Instruct the scheduled item to re-schedule itself given new state data and
 | 
						|
	// the earliest time at which the outside system thinks the operation should
 | 
						|
	// be scheduled for.
 | 
						|
	Reschedule(earliest time.Time, future TargetState)
 | 
						|
}
 | 
						|
 | 
						|
// healthScheduler is an implementation of scheduler that uses health data
 | 
						|
// provided by the target field as well as unreachability counts to determine
 | 
						|
// when to next schedule an operation.
 | 
						|
//
 | 
						|
// The type is almost capable of being used with default initialization, except
 | 
						|
// that a target field must be provided for which the system compares current
 | 
						|
// health against future proposed values.
 | 
						|
type healthScheduler struct {
 | 
						|
	scheduledFor     time.Time
 | 
						|
	target           healthReporter
 | 
						|
	time             utility.Time
 | 
						|
	unreachableCount int
 | 
						|
}
 | 
						|
 | 
						|
func (s healthScheduler) ScheduledFor() time.Time {
 | 
						|
	return s.scheduledFor
 | 
						|
}
 | 
						|
 | 
						|
// Reschedule, like the protocol described in scheduler, uses the current and
 | 
						|
// proposed future health state to determine how and when a given subject is to
 | 
						|
// be scheduled.
 | 
						|
//
 | 
						|
// If a subject has been at given moment marked as unhealthy, an exponential
 | 
						|
// backoff scheme is applied to it.  The reason for this backoff is to ensure
 | 
						|
// that known-healthy targets can consume valuable request queuing resources
 | 
						|
// first.  Depending on the retrieval interval and number of consecutive
 | 
						|
// unhealthy markings, the query of these unhealthy individuals may come before
 | 
						|
// the healthy ones for a short time to help ensure expeditious retrieval.
 | 
						|
// The inflection point that drops these to the back of the queue is beneficial
 | 
						|
// to save resources in the long-run.
 | 
						|
//
 | 
						|
// If a subject is healthy, its next scheduling opportunity is set to
 | 
						|
// earliest, for this ensures fair querying of all remaining healthy targets and
 | 
						|
// removes bias in the ordering.  In order for the anti-bias value to have any
 | 
						|
// value, the earliest opportunity should be set to a value that is constant
 | 
						|
// for a given batch of subjects who are to be scraped on a given interval.
 | 
						|
func (s *healthScheduler) Reschedule(e time.Time, f TargetState) {
 | 
						|
	currentState := s.target.State()
 | 
						|
	// XXX: Handle metrics surrounding health.
 | 
						|
	switch currentState {
 | 
						|
	case UNKNOWN, UNREACHABLE:
 | 
						|
		switch f {
 | 
						|
		case ALIVE:
 | 
						|
			s.unreachableCount = 0
 | 
						|
			break
 | 
						|
		case UNREACHABLE:
 | 
						|
			s.unreachableCount++
 | 
						|
			break
 | 
						|
		}
 | 
						|
	case ALIVE:
 | 
						|
		switch f {
 | 
						|
		case UNREACHABLE:
 | 
						|
			s.unreachableCount++
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if s.unreachableCount == 0 {
 | 
						|
		s.scheduledFor = e
 | 
						|
	} else {
 | 
						|
		backoff := MAXIMUM_BACKOFF_VALUE
 | 
						|
		exponential := time.Duration(math.Pow(DEFAULT_BACKOFF_VALUE, float64(s.unreachableCount))) * DEFAULT_BACKOFF_VALUE_UNIT
 | 
						|
		if backoff > exponential {
 | 
						|
			backoff = exponential
 | 
						|
		}
 | 
						|
 | 
						|
		s.scheduledFor = s.time.Now().Add(backoff)
 | 
						|
	}
 | 
						|
}
 |