Alerting: State manager to use clock (#51219)

* manager to use clock, to be able to mock real time
This commit is contained in:
Yuriy Tseretyan 2022-06-22 12:18:42 -04:00 committed by GitHub
parent 405df77e3e
commit 4b42cd3c1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 18 additions and 12 deletions

View File

@ -151,7 +151,7 @@ func (ng *AlertNG) init() error {
appUrl = nil appUrl = nil
} }
stateManager := state.NewManager(ng.Log, ng.Metrics.GetStateMetrics(), appUrl, store, store, ng.dashboardService, ng.imageService) stateManager := state.NewManager(ng.Log, ng.Metrics.GetStateMetrics(), appUrl, store, store, ng.dashboardService, ng.imageService, clock.New())
scheduler := schedule.NewScheduler(schedCfg, ng.ExpressionService, appUrl, stateManager, ng.bus) scheduler := schedule.NewScheduler(schedCfg, ng.ExpressionService, appUrl, stateManager, ng.bus)
ng.stateManager = stateManager ng.stateManager = stateManager

View File

@ -108,7 +108,7 @@ func TestWarmStateCache(t *testing.T) {
Metrics: testMetrics.GetSchedulerMetrics(), Metrics: testMetrics.GetSchedulerMetrics(),
AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests. AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests.
} }
st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, &dashboards.FakeDashboardService{}, &image.NoopImageService{}) st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, &dashboards.FakeDashboardService{}, &image.NoopImageService{}, clock.NewMock())
st.Warm(ctx) st.Warm(ctx)
t.Run("instance cache has expected entries", func(t *testing.T) { t.Run("instance cache has expected entries", func(t *testing.T) {
@ -160,7 +160,7 @@ func TestAlertingTicker(t *testing.T) {
disabledOrgID: {}, disabledOrgID: {},
}, },
} }
st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, &dashboards.FakeDashboardService{}, &image.NoopImageService{}) st := state.NewManager(schedCfg.Logger, testMetrics.GetStateMetrics(), nil, dbstore, dbstore, &dashboards.FakeDashboardService{}, &image.NoopImageService{}, clock.NewMock())
appUrl := &url.URL{ appUrl := &url.URL{
Scheme: "http", Scheme: "http",
Host: "localhost", Host: "localhost",

View File

@ -958,7 +958,7 @@ func setupScheduler(t *testing.T, rs store.RuleStore, is store.InstanceStore, ac
Metrics: m.GetSchedulerMetrics(), Metrics: m.GetSchedulerMetrics(),
AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests. AdminConfigPollInterval: 10 * time.Minute, // do not poll in unit tests.
} }
st := state.NewManager(schedCfg.Logger, m.GetStateMetrics(), nil, rs, is, &dashboards.FakeDashboardService{}, &image.NoopImageService{}) st := state.NewManager(schedCfg.Logger, m.GetStateMetrics(), nil, rs, is, &dashboards.FakeDashboardService{}, &image.NoopImageService{}, clock.NewMock())
appUrl := &url.URL{ appUrl := &url.URL{
Scheme: "http", Scheme: "http",
Host: "localhost", Host: "localhost",

View File

@ -9,6 +9,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/benbjohnson/clock"
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
@ -35,6 +36,7 @@ type Manager struct {
log log.Logger log log.Logger
metrics *metrics.State metrics *metrics.State
clock clock.Clock
cache *cache cache *cache
quit chan struct{} quit chan struct{}
ResendDelay time.Duration ResendDelay time.Duration
@ -47,7 +49,7 @@ type Manager struct {
func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL, func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL,
ruleStore store.RuleStore, instanceStore store.InstanceStore, ruleStore store.RuleStore, instanceStore store.InstanceStore,
dashboardService dashboards.DashboardService, imageService image.ImageService) *Manager { dashboardService dashboards.DashboardService, imageService image.ImageService, clock clock.Clock) *Manager {
manager := &Manager{ manager := &Manager{
cache: newCache(logger, metrics, externalURL), cache: newCache(logger, metrics, externalURL),
quit: make(chan struct{}), quit: make(chan struct{}),
@ -58,6 +60,7 @@ func NewManager(logger log.Logger, metrics *metrics.State, externalURL *url.URL,
instanceStore: instanceStore, instanceStore: instanceStore,
dashboardService: dashboardService, dashboardService: dashboardService,
imageService: imageService, imageService: imageService,
clock: clock,
} }
go manager.recordMetrics() go manager.recordMetrics()
return manager return manager
@ -272,14 +275,14 @@ func (st *Manager) recordMetrics() {
// TODO: parameterize? // TODO: parameterize?
// Setting to a reasonable default scrape interval for Prometheus. // Setting to a reasonable default scrape interval for Prometheus.
dur := time.Duration(15) * time.Second dur := time.Duration(15) * time.Second
ticker := time.NewTicker(dur) ticker := st.clock.Ticker(dur)
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
st.log.Debug("recording state cache metrics", "now", time.Now()) st.log.Debug("recording state cache metrics", "now", st.clock.Now())
st.cache.recordMetrics() st.cache.recordMetrics()
case <-st.quit: case <-st.quit:
st.log.Debug("stopping state cache metrics recording", "now", time.Now()) st.log.Debug("stopping state cache metrics recording", "now", st.clock.Now())
ticker.Stop() ticker.Stop()
return return
} }

View File

@ -9,6 +9,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/benbjohnson/clock"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/ngalert/eval" "github.com/grafana/grafana/pkg/services/ngalert/eval"
@ -93,7 +95,7 @@ func Test_maybeNewImage(t *testing.T) {
imageService := &CountingImageService{} imageService := &CountingImageService{}
mgr := NewManager(log.NewNopLogger(), &metrics.State{}, nil, mgr := NewManager(log.NewNopLogger(), &metrics.State{}, nil,
&store.FakeRuleStore{}, &store.FakeInstanceStore{}, &store.FakeRuleStore{}, &store.FakeInstanceStore{},
&dashboards.FakeDashboardService{}, imageService) &dashboards.FakeDashboardService{}, imageService, clock.NewMock())
err := mgr.maybeTakeScreenshot(context.Background(), &ngmodels.AlertRule{}, test.state, test.oldState) err := mgr.maybeTakeScreenshot(context.Background(), &ngmodels.AlertRule{}, test.state, test.oldState)
require.NoError(t, err) require.NoError(t, err)
if !test.shouldScreenshot { if !test.shouldScreenshot {

View File

@ -8,6 +8,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/benbjohnson/clock"
"github.com/grafana/grafana-plugin-sdk-go/data" "github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -35,7 +36,7 @@ func TestDashboardAnnotations(t *testing.T) {
ctx := context.Background() ctx := context.Background()
_, dbstore := tests.SetupTestEnv(t, 1) _, dbstore := tests.SetupTestEnv(t, 1)
st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, &dashboards.FakeDashboardService{}, &image.NoopImageService{}) st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, &dashboards.FakeDashboardService{}, &image.NoopImageService{}, clock.New())
fakeAnnoRepo := store.NewFakeAnnotationsRepo() fakeAnnoRepo := store.NewFakeAnnotationsRepo()
annotations.SetRepository(fakeAnnoRepo) annotations.SetRepository(fakeAnnoRepo)
@ -1880,7 +1881,7 @@ func TestProcessEvalResults(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
st := state.NewManager(log.New("test_state_manager"), testMetrics.GetStateMetrics(), nil, nil, &store.FakeInstanceStore{}, &dashboards.FakeDashboardService{}, &image.NotAvailableImageService{}) st := state.NewManager(log.New("test_state_manager"), testMetrics.GetStateMetrics(), nil, nil, &store.FakeInstanceStore{}, &dashboards.FakeDashboardService{}, &image.NotAvailableImageService{}, clock.New())
t.Run(tc.desc, func(t *testing.T) { t.Run(tc.desc, func(t *testing.T) {
fakeAnnoRepo := store.NewFakeAnnotationsRepo() fakeAnnoRepo := store.NewFakeAnnotationsRepo()
annotations.SetRepository(fakeAnnoRepo) annotations.SetRepository(fakeAnnoRepo)
@ -1998,7 +1999,7 @@ func TestStaleResultsHandler(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
ctx := context.Background() ctx := context.Background()
st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, &dashboards.FakeDashboardService{}, &image.NoopImageService{}) st := state.NewManager(log.New("test_stale_results_handler"), testMetrics.GetStateMetrics(), nil, dbstore, dbstore, &dashboards.FakeDashboardService{}, &image.NoopImageService{}, clock.New())
st.Warm(ctx) st.Warm(ctx)
existingStatesForRule := st.GetStatesForRuleUID(rule.OrgID, rule.UID) existingStatesForRule := st.GetStatesForRuleUID(rule.OrgID, rule.UID)