// analyzeWithPrevious returns false if primary deviates in the specified direction compared to the previous deployment.
// Return an error if the evaluation could not be executed normally.
// elapsedTime is used to compare metrics at the same point in time after the analysis has started.
analyzeWithPrevious returns false if primary deviates in the specified direction compared to the previous deployment.
Return an error if the evaluation could not be executed normally.
elapsedTime is used to compare metrics at the same point in time after the analysis has started.
// analyzeWithPrevious returns false if primary deviates in the specified direction compared to the previous deployment . // Return an error if the evaluation could not be executed normally . // elapsedTime is used to compare metrics at the same point in time after the analysis has started .
func (a *metricsAnalyzer) analyzeWithPrevious(ctx context.Context) (expected, firstDeploy bool, err error) {
	now := time.Now()
	queryRange := metrics.QueryRange{
		From: now.Add(-a.cfg.Interval.Duration()),
		To:   now,
	}
	points, err := a.provider.QueryPoints(ctx, a.cfg.Query, queryRange)
	if err != nil {
		return false, false, fmt.Errorf("failed to run query: %w: performed query: %q", err, a.cfg.Query)
	}
	pointsCount := len(points)
	a.logPersister.Infof("[%s] Got %d data points for current Primary from the query: %q", a.id, pointsCount, a.cfg.Query)
	values := make([]float64, 0, pointsCount)
	for i := range points {
		values = append(values, points[i].Value)
	}
	prevMetadata, err := a.analysisResultStore.GetLatestAnalysisResult(ctx)
	if errors.Is(err, analysisresultstore.ErrNotFound) {
		return false, true, nil
	}
	if err != nil {
		return false, false, fmt.Errorf("failed to fetch the most recent successful analysis metadata: %w", err)
	}
	elapsedTime := now.Sub(a.stageStartTime)
	prevTo := time.Unix(prevMetadata.StartTime, 0).Add(elapsedTime)
	prevFrom := prevTo.Add(-a.cfg.Interval.Duration())
	prevQueryRange := metrics.QueryRange{
		From: prevFrom,
		To:   prevTo,
	}
	prevPoints, err := a.provider.QueryPoints(ctx, a.cfg.Query, prevQueryRange)
	if err != nil {
		return false, false, fmt.Errorf("failed to run query to fetch metrics for the previous deployment: %w: performed query: %q", err, a.cfg.Query)
	}
	prevPointsCount := len(prevPoints)
	a.logPersister.Infof("[%s] Got %d data points for previous Primary from the query: %q", a.id, prevPointsCount, a.cfg.Query)
	prevValues := make([]float64, 0, prevPointsCount)
	for i := range prevPoints {
		prevValues = append(prevValues, prevPoints[i].Value)
	}
	expected, err = compare(values, prevValues, a.cfg.Deviation)
	if err != nil {
		a.logPersister.Errorf("[%s] Failed to compare data points: %v", a.id, err)
		a.logPersister.Infof("[%s] Performed query: %q", a.id, a.cfg.Query)
		return false, false, err
	}
	if !expected {
		a.logPersister.Errorf("[%s] The difference between Current Primary and Previous one is statistically significant", a.id)
		a.logPersister.Infof("[%s] Performed query range for current Primary: %q", a.id, &queryRange)
		a.logPersister.Infof("[%s] Performed query range for previous Primary: %q", a.id, &prevQueryRange)
		a.logPersister.Infof("[%s] Performed query: %q", a.id, a.cfg.Query)
		a.logPersister.Infof("[%s] Current data points acquired:", a.id)
		for i := range points {
			a.logPersister.Infof("[%s] %s", a.id, &points[i])
		}
		a.logPersister.Infof("[%s] Previous data points acquired:", a.id)
		for i := range prevPoints {
			a.logPersister.Infof("[%s] %s", a.id, &prevPoints[i])
		}
		return false, false, nil
	}
	return true, false, nil
}
func ( a * metricsAnalyzer ) analyzeWithPrevious ( ctx context . Context ) ( expected , firstDeploy bool , err error ) { now := time . Now ( ) queryRange := metrics . QueryRange { From : now . Add ( - a . cfg . Interval . Duration ( ) ) , To : now , } points , err := a . provider . QueryPoints ( ctx , a . cfg . Query , queryRange ) if err != nil { return false , false , fmt . Errorf ( " " , err , a . cfg . Query ) } pointsCount := len ( points ) a . logPersister . Infof ( " " , a . id , pointsCount , a . cfg . Query ) values := make ( [ ] float64 , 0 , pointsCount ) for i := range points { values = append ( values , points [ i ] . Value ) } prevMetadata , err := a . analysisResultStore . GetLatestAnalysisResult ( ctx ) if errors . Is ( err , analysisresultstore . ErrNotFound ) { return false , true , nil } if err != nil { return false , false , fmt . Errorf ( " " , err ) } elapsedTime := now . Sub ( a . stageStartTime ) prevTo := time . Unix ( prevMetadata . StartTime , 0 ) . Add ( elapsedTime ) prevFrom := prevTo . Add ( - a . cfg . Interval . Duration ( ) ) prevQueryRange := metrics . QueryRange { From : prevFrom , To : prevTo , } prevPoints , err := a . provider . QueryPoints ( ctx , a . cfg . Query , prevQueryRange ) if err != nil { return false , false , fmt . Errorf ( " " , err , a . cfg . Query ) } prevPointsCount := len ( prevPoints ) a . logPersister . Infof ( " " , a . id , prevPointsCount , a . cfg . Query ) prevValues := make ( [ ] float64 , 0 , prevPointsCount ) for i := range prevPoints { prevValues = append ( prevValues , prevPoints [ i ] . Value ) } expected , err = compare ( values , prevValues , a . cfg . Deviation ) if err != nil { a . logPersister . Errorf ( " " , a . id , err ) a . logPersister . Infof ( " " , a . id , a . cfg . Query ) return false , false , err } if ! expected { a . logPersister . Errorf ( " " , a . id ) a . logPersister . Infof ( " " , a . id , & queryRange ) a . logPersister . Infof ( " " , a . id , & prevQueryRange ) a . logPersister . Infof ( " " , a . id , a . cfg . Query ) a . logPersister . Infof ( " " , a . id ) for i := range points { a . logPersister . Infof ( " " , a . id , & points [ i ] ) } a . logPersister . Infof ( " " , a . id ) for i := range prevPoints { a . logPersister . Infof ( " " , a . id , & prevPoints [ i ] ) } return false , false , nil } return true , false , nil }
analyzeWithPrevious returns false if primary deviates in the specified direction compared to the previous deployment.
analyzeWithPrevious returns false if primary deviates in the specified direction compared to the previous deployment .
// Compare it with the previous metrics when the same amount of time as now has passed since the start of the stage.