-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: notifier metric alive count (#1130)
- Loading branch information
1 parent
83c63a0
commit b1aaf83
Showing
11 changed files
with
231 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package notifier | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/moira-alert/moira" | ||
"github.com/moira-alert/moira/metrics" | ||
) | ||
|
||
// AliveWatcher is responsible for checking notifier state and marking notifier.alive metrics. | ||
type AliveWatcher struct { | ||
logger moira.Logger | ||
database moira.Database | ||
checkNotifierStateTimeout time.Duration | ||
notifierMetrics *metrics.NotifierMetrics | ||
} | ||
|
||
// NewAliveWatcher is an initializer for AliveWatcher. | ||
func NewAliveWatcher( | ||
logger moira.Logger, | ||
database moira.Database, | ||
checkNotifierStateTimeout time.Duration, | ||
notifierMetrics *metrics.NotifierMetrics, | ||
) *AliveWatcher { | ||
return &AliveWatcher{ | ||
logger: logger, | ||
database: database, | ||
checkNotifierStateTimeout: checkNotifierStateTimeout, | ||
notifierMetrics: notifierMetrics, | ||
} | ||
} | ||
|
||
// Start starts the checking loop in separate goroutine. | ||
// Use context.WithCancel, context.WithTimeout etc. to terminate check loop. | ||
func (watcher *AliveWatcher) Start(ctx context.Context) { | ||
go watcher.stateChecker(ctx) | ||
} | ||
|
||
func (watcher *AliveWatcher) stateChecker(ctx context.Context) { | ||
watcher.logger.Info(). | ||
Interface("check_timeout_seconds", watcher.checkNotifierStateTimeout.Seconds()). | ||
Msg("Moira Notifier alive watcher started") | ||
|
||
ticker := time.NewTicker(watcher.checkNotifierStateTimeout) | ||
|
||
for { | ||
select { | ||
case <-ctx.Done(): | ||
watcher.logger.Info().Msg("Moira Notifier alive watcher stopped") | ||
return | ||
case <-ticker.C: | ||
watcher.checkNotifierState() | ||
} | ||
} | ||
} | ||
|
||
func (watcher *AliveWatcher) checkNotifierState() { | ||
state, _ := watcher.database.GetNotifierState() | ||
if state != moira.SelfStateOK { | ||
watcher.notifierMetrics.MarkNotifierIsAlive(false) | ||
return | ||
} | ||
|
||
watcher.notifierMetrics.MarkNotifierIsAlive(true) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package notifier | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"testing" | ||
"time" | ||
|
||
"github.com/moira-alert/moira" | ||
"github.com/moira-alert/moira/metrics" | ||
. "github.com/smartystreets/goconvey/convey" | ||
"go.uber.org/mock/gomock" | ||
|
||
mock_moira_alert "github.com/moira-alert/moira/mock/moira-alert" | ||
mock_metrics "github.com/moira-alert/moira/mock/moira-alert/metrics" | ||
) | ||
|
||
func initAliveMeter(mockCtrl *gomock.Controller) (*mock_metrics.MockRegistry, *mock_metrics.MockMeter) { | ||
mockRegistry := mock_metrics.NewMockRegistry(mockCtrl) | ||
mockAliveMeter := mock_metrics.NewMockMeter(mockCtrl) | ||
|
||
mockRegistry.EXPECT().NewMeter(gomock.Any()).Times(5) | ||
mockRegistry.EXPECT().NewHistogram(gomock.Any()).Times(3) | ||
mockRegistry.EXPECT().NewMeter("", "alive").Return(mockAliveMeter) | ||
|
||
return mockRegistry, mockAliveMeter | ||
} | ||
|
||
func TestAliveWatcher_checkNotifierState(t *testing.T) { | ||
mockCtrl := gomock.NewController(t) | ||
defer mockCtrl.Finish() | ||
|
||
dataBase := mock_moira_alert.NewMockDatabase(mockCtrl) | ||
|
||
mockRegistry, mockAliveMeter := initAliveMeter(mockCtrl) | ||
testNotifierMetrics := metrics.ConfigureNotifierMetrics(mockRegistry, "") | ||
|
||
aliveWatcher := NewAliveWatcher(nil, dataBase, 0, testNotifierMetrics) | ||
|
||
Convey("checkNotifierState", t, func() { | ||
Convey("when OK", func() { | ||
dataBase.EXPECT().GetNotifierState().Return(moira.SelfStateOK, nil) | ||
mockAliveMeter.EXPECT().Mark(int64(1)) | ||
|
||
aliveWatcher.checkNotifierState() | ||
}) | ||
|
||
Convey("when not OK state and no errors", func() { | ||
notOKStates := []string{moira.SelfStateERROR, "err", "bad", "", "1"} | ||
|
||
for _, badState := range notOKStates { | ||
dataBase.EXPECT().GetNotifierState().Return(badState, nil) | ||
mockAliveMeter.EXPECT().Mark(int64(0)) | ||
|
||
aliveWatcher.checkNotifierState() | ||
} | ||
}) | ||
|
||
Convey("when not OK state and errors", func() { | ||
notOKState := "" | ||
givenErrors := []error{ | ||
errors.New("one error"), | ||
errors.New("another error"), | ||
} | ||
|
||
for _, err := range givenErrors { | ||
dataBase.EXPECT().GetNotifierState().Return(notOKState, err) | ||
mockAliveMeter.EXPECT().Mark(int64(0)) | ||
|
||
aliveWatcher.checkNotifierState() | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
func TestAliveWatcher_Start(t *testing.T) { | ||
mockCtrl := gomock.NewController(t) | ||
defer mockCtrl.Finish() | ||
|
||
logger := mock_moira_alert.NewMockLogger(mockCtrl) | ||
eventsBuilder := mock_moira_alert.NewMockEventBuilder(mockCtrl) | ||
logger.EXPECT().Info().Return(eventsBuilder).AnyTimes() | ||
|
||
dataBase := mock_moira_alert.NewMockDatabase(mockCtrl) | ||
|
||
const ( | ||
testCheckNotifierStateTimeout = time.Second | ||
) | ||
|
||
mockRegistry, mockAliveMeter := initAliveMeter(mockCtrl) | ||
testNotifierMetrics := metrics.ConfigureNotifierMetrics(mockRegistry, "") | ||
|
||
aliveWatcher := NewAliveWatcher(logger, dataBase, testCheckNotifierStateTimeout, testNotifierMetrics) | ||
|
||
Convey("AliveWatcher stops on cancel", t, func() { | ||
eventsBuilder.EXPECT(). | ||
Interface("check_timeout_seconds", testCheckNotifierStateTimeout.Seconds()). | ||
Return(eventsBuilder) | ||
eventsBuilder.EXPECT().Msg("Moira Notifier alive watcher started") | ||
eventsBuilder.EXPECT().Msg("Moira Notifier alive watcher stopped") | ||
|
||
dataBase.EXPECT().GetNotifierState().Return(moira.SelfStateOK, nil).AnyTimes() | ||
mockAliveMeter.EXPECT().Mark(int64(1)).AnyTimes() | ||
|
||
ctx, cancel := context.WithCancel(context.Background()) | ||
aliveWatcher.Start(ctx) | ||
|
||
time.Sleep(time.Second * 3) | ||
cancel() | ||
time.Sleep(time.Millisecond) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.