feat(alerting): moved alerting models back to alerting package, models is more for storage dtos
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
package tsdb
|
||||
|
||||
import "errors"
|
||||
|
||||
type Batch struct {
|
||||
DataSourceId int64
|
||||
Queries QuerySlice
|
||||
Depends map[string]bool
|
||||
Done bool
|
||||
Started bool
|
||||
}
|
||||
|
||||
type BatchSlice []*Batch
|
||||
|
||||
func newBatch(dsId int64, queries QuerySlice) *Batch {
|
||||
return &Batch{
|
||||
DataSourceId: dsId,
|
||||
Queries: queries,
|
||||
Depends: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (bg *Batch) process(context *QueryContext) {
|
||||
executor := getExecutorFor(bg.Queries[0].DataSource)
|
||||
|
||||
if executor == nil {
|
||||
bg.Done = true
|
||||
result := &BatchResult{
|
||||
Error: errors.New("Could not find executor for data source type " + bg.Queries[0].DataSource.Type),
|
||||
QueryResults: make(map[string]*QueryResult),
|
||||
}
|
||||
for _, query := range bg.Queries {
|
||||
result.QueryResults[query.RefId] = &QueryResult{Error: result.Error}
|
||||
}
|
||||
context.ResultsChan <- result
|
||||
return
|
||||
}
|
||||
|
||||
res := executor.Execute(bg.Queries, context)
|
||||
bg.Done = true
|
||||
context.ResultsChan <- res
|
||||
}
|
||||
|
||||
func (bg *Batch) addQuery(query *Query) {
|
||||
bg.Queries = append(bg.Queries, query)
|
||||
}
|
||||
|
||||
func (bg *Batch) allDependenciesAreIn(context *QueryContext) bool {
|
||||
for key := range bg.Depends {
|
||||
if _, exists := context.Results[key]; !exists {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func getBatches(req *Request) (BatchSlice, error) {
|
||||
batches := make(BatchSlice, 0)
|
||||
|
||||
for _, query := range req.Queries {
|
||||
if foundBatch := findMatchingBatchGroup(query, batches); foundBatch != nil {
|
||||
foundBatch.addQuery(query)
|
||||
} else {
|
||||
newBatch := newBatch(query.DataSource.Id, QuerySlice{query})
|
||||
batches = append(batches, newBatch)
|
||||
|
||||
for _, refId := range query.Depends {
|
||||
for _, batch := range batches {
|
||||
for _, batchQuery := range batch.Queries {
|
||||
if batchQuery.RefId == refId {
|
||||
newBatch.Depends[refId] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return batches, nil
|
||||
}
|
||||
|
||||
func findMatchingBatchGroup(query *Query, batches BatchSlice) *Batch {
|
||||
for _, batch := range batches {
|
||||
if batch.DataSourceId == query.DataSource.Id {
|
||||
return batch
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package tsdb
|
||||
|
||||
type Executor interface {
|
||||
Execute(queries QuerySlice, context *QueryContext) *BatchResult
|
||||
}
|
||||
|
||||
var registry map[string]GetExecutorFn
|
||||
|
||||
type GetExecutorFn func(dsInfo *DataSourceInfo) Executor
|
||||
|
||||
func init() {
|
||||
registry = make(map[string]GetExecutorFn)
|
||||
}
|
||||
|
||||
func getExecutorFor(dsInfo *DataSourceInfo) Executor {
|
||||
if fn, exists := registry[dsInfo.Type]; exists {
|
||||
return fn(dsInfo)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RegisterExecutor(dsType string, fn GetExecutorFn) {
|
||||
registry[dsType] = fn
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package tsdb
|
||||
|
||||
import "time"
|
||||
|
||||
type TimeRange struct {
|
||||
From time.Time
|
||||
To time.Time
|
||||
}
|
||||
|
||||
type Request struct {
|
||||
TimeRange TimeRange
|
||||
MaxDataPoints int
|
||||
Queries QuerySlice
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
BatchTimings []*BatchTiming
|
||||
Results map[string]*QueryResult
|
||||
}
|
||||
|
||||
type DataSourceInfo struct {
|
||||
Id int64
|
||||
Name string
|
||||
Type string
|
||||
Url string
|
||||
Password string
|
||||
User string
|
||||
Database string
|
||||
BasicAuth bool
|
||||
BasicAuthUser string
|
||||
BasicAuthPassword string
|
||||
}
|
||||
|
||||
type BatchTiming struct {
|
||||
TimeElapsed int64
|
||||
}
|
||||
|
||||
type BatchResult struct {
|
||||
Error error
|
||||
QueryResults map[string]*QueryResult
|
||||
Timings *BatchTiming
|
||||
}
|
||||
|
||||
type QueryResult struct {
|
||||
Error error
|
||||
RefId string
|
||||
Series TimeSeriesSlice
|
||||
}
|
||||
|
||||
type TimeSeries struct {
|
||||
Name string
|
||||
Points [][2]float64
|
||||
}
|
||||
|
||||
type TimeSeriesSlice []*TimeSeries
|
||||
|
||||
func NewTimeSeries(name string, points [][2]float64) *TimeSeries {
|
||||
return &TimeSeries{
|
||||
Name: name,
|
||||
Points: points,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package tsdb
|
||||
|
||||
type Query struct {
|
||||
RefId string
|
||||
Query string
|
||||
Depends []string
|
||||
DataSource *DataSourceInfo
|
||||
Results []*TimeSeries
|
||||
Exclude bool
|
||||
}
|
||||
|
||||
type QuerySlice []*Query
|
||||
@@ -0,0 +1,21 @@
|
||||
package tsdb
|
||||
|
||||
import "sync"
|
||||
|
||||
type QueryContext struct {
|
||||
TimeRange TimeRange
|
||||
Queries QuerySlice
|
||||
Results map[string]*QueryResult
|
||||
ResultsChan chan *BatchResult
|
||||
Lock sync.RWMutex
|
||||
BatchWaits sync.WaitGroup
|
||||
}
|
||||
|
||||
func NewQueryContext(queries QuerySlice, timeRange TimeRange) *QueryContext {
|
||||
return &QueryContext{
|
||||
TimeRange: timeRange,
|
||||
Queries: queries,
|
||||
ResultsChan: make(chan *BatchResult),
|
||||
Results: make(map[string]*QueryResult),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package tsdb
|
||||
|
||||
func HandleRequest(req *Request) (*Response, error) {
|
||||
context := NewQueryContext(req.Queries, req.TimeRange)
|
||||
|
||||
batches, err := getBatches(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
currentlyExecuting := 0
|
||||
|
||||
for _, batch := range batches {
|
||||
if len(batch.Depends) == 0 {
|
||||
currentlyExecuting += 1
|
||||
batch.Started = true
|
||||
go batch.process(context)
|
||||
}
|
||||
}
|
||||
|
||||
response := &Response{}
|
||||
|
||||
for currentlyExecuting != 0 {
|
||||
select {
|
||||
case batchResult := <-context.ResultsChan:
|
||||
currentlyExecuting -= 1
|
||||
|
||||
response.BatchTimings = append(response.BatchTimings, batchResult.Timings)
|
||||
|
||||
for refId, result := range batchResult.QueryResults {
|
||||
context.Results[refId] = result
|
||||
}
|
||||
|
||||
for _, batch := range batches {
|
||||
// not interested in started batches
|
||||
if batch.Started {
|
||||
continue
|
||||
}
|
||||
|
||||
if batch.allDependenciesAreIn(context) {
|
||||
currentlyExecuting += 1
|
||||
batch.Started = true
|
||||
go batch.process(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response.Results = context.Results
|
||||
return response, nil
|
||||
}
|
||||
Reference in New Issue
Block a user