blob: 93b2c715644ced54f17d511113fc18279594a454 [file]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package analyzer
import (
"context"
"sync"
"time"
"infra/appengine/sheriff-o-matic/som/client"
"infra/monitoring/messages"
"go.chromium.org/luci/gae/service/info"
)
const (
// StepCompletedRun is a synthetic step name used to indicate the build run is complete.
StepCompletedRun = "completed run"
prodAppID = "sheriff-o-matic"
)
// Analyzer runs the process of checking builder groups, builders, test results and so on,
// in order to produce alerts.
type Analyzer struct {
// MaxRecentBuilds is the maximum number of recent builds to check, per builder.
MaxRecentBuilds int
// MinRecentBuilds is the minimum number of recent builds to check, per builder.
MinRecentBuilds int
// HungBuilerThresh is the maxumum length of time a builder may be in state "building"
// before triggering a "hung builder" alert.
HungBuilderThresh time.Duration
// OfflineBuilderThresh is the maximum length of time a builder may be in state "offline"
// before triggering an "offline builder" alert.
OfflineBuilderThresh time.Duration
// IdleBuilderCountThresh is the maximum number of builds a builder may have in queue
// while in the "idle" state before triggering an "idle builder" alert.
IdleBuilderCountThresh int64
// rslck protects revisionSummaries from concurrent access.
rslck *sync.Mutex
revisionSummaries map[string]messages.RevisionSummary
// Now is useful for mocking the system clock in testing and simulating time
// during replay.
Now func() time.Time
// Mock these out in tests.
CrBug client.CrBug
FindIt client.FindIt
}
// New returns a new Analyzer. If client is nil, it assigns a default implementation.
// maxBuilds is the maximum number of builds to check, per builder.
func New(minBuilds, maxBuilds int) *Analyzer {
return &Analyzer{
MaxRecentBuilds: maxBuilds,
MinRecentBuilds: minBuilds,
HungBuilderThresh: 3 * time.Hour,
OfflineBuilderThresh: 90 * time.Minute,
IdleBuilderCountThresh: 50,
rslck: &sync.Mutex{},
revisionSummaries: map[string]messages.RevisionSummary{},
Now: func() time.Time {
return time.Now()
},
}
}
// GetRevisionSummaries returns a slice of RevisionSummaries for the list of hashes.
func (a *Analyzer) GetRevisionSummaries(hashes []string) ([]*messages.RevisionSummary, error) {
ret := []*messages.RevisionSummary{}
for _, h := range hashes {
a.rslck.Lock()
s, ok := a.revisionSummaries[h]
a.rslck.Unlock()
if !ok {
continue
}
ret = append(ret, &s)
}
return ret, nil
}
// CreateAnalyzer creates a new analyzer and set its service clients.
func CreateAnalyzer(c context.Context) *Analyzer {
a := New(5, 100)
setServiceClients(c, a)
return a
}
func setServiceClients(c context.Context, a *Analyzer) {
if info.AppID(c) == prodAppID {
findIt, crBug, _ := client.ProdClients(c)
a.CrBug = crBug
a.FindIt = findIt
} else {
findIt, crBug, _ := client.StagingClients(c)
a.CrBug = crBug
a.FindIt = findIt
}
}